package com.ruoyi.system.business.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.FormatUtil;
import com.ruoyi.common.utils.MyDateUtils;
import com.ruoyi.system.business.QsTagImportBusinessService;
import com.ruoyi.system.business.vo.DrInfoImport;
import com.ruoyi.system.business.vo.QstagModbusTcp;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.DrtypeinfoMapper;
import com.ruoyi.system.mapper.DrtypemodeMapper;
import com.ruoyi.system.mapper.RegGroupMapper;
import com.ruoyi.system.mapper.SubMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.impl.AlarmtypeServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class QsTagImportBusinessServiceImpl implements QsTagImportBusinessService {

    private static final Logger log = LoggerFactory.getLogger(AlarmtypeServiceImpl.class);
    @Value("${jobTask.needStart}")
    private boolean jobNeedStart;
    @Value("${centralDatabase.dbName}")
    private String centralDatabase;
    @Resource
    private IQstagService qstagService;
    @Resource
    private IRegService regService;//变量Service
    @Resource
    private IDrtypeinfoService drtypeinfoService;
    @Resource
    private DrtypeinfoMapper drtypeinfoMapper;
    @Resource
    private DrtypemodeMapper drtypemodeMapper;
    @Resource
    private IDrinfoService drinfoService;
    @Resource
    private IDlldrInfoService dlldrInfoService;
    @Resource
    private ParamTypeService paramTypeService;
    @Resource
    private HomePageService homePageService;
    @Resource
    private RegGroupMapper regGroupMapper;
    @Resource
    private SubMapper subMapper;
    private SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd");
    @Resource
    private ISubService subService;
    @Resource
    private ISubinfoService subinfoService;

    /**
     * DEV环境下，检查excel表格中点表与数据库中qstag表的差异性，以便获取变更内容，然后针对进行处理。
     * DEV环境下，只是检查数据的异同，检查完毕后直接返回
     * @param dbName
     * @param rawList
     * @return
     */
    private AjaxResult checkTheDifferencesOfData(String dbName, List<QstagModbusTcp> rawList){
        int count = 0;//序号
        List<Qstag> allList = qstagService.findAll(dbName);
        Map<String,List<Qstag>> qsTagMap = new HashMap<>();
        if(allList != null && allList.size() > 0){
            List<Qstag> newAllList = allList.stream()
                    .filter(qstag -> qstag.getItemid() != null)
                    .filter(qstag -> qstag.getTagnameCN() != null)
                    .filter(qstag -> !"local".equals(qstag.getItemid()))
                    .collect(Collectors.toList());//过滤itemid != 'local'
            qsTagMap = newAllList.stream().collect(Collectors.groupingBy(Qstag::getItemid));//11111111111111111111111111
            //qsTagMap = newAllList.stream().collect(Collectors.groupingBy(Qstag::getTagnameCN));
        }
        List<RegGroup> groupList = regGroupMapper.findAllRegGroup(dbName);//获取分组：select * from `${dbName}`.reg_group where 1 = 1
        Map<String,RegGroup> groupMap = new HashMap<>();
        if(groupList != null){
            groupList.forEach(regGroup -> {
                groupMap.put(String.valueOf(regGroup.getGroupName()),regGroup);
            });
        }

        List<Subinfo> subInfoAllList = subinfoService.findAllObject(dbName);
        Map<String,Long> regSubInfoMap = subinfoService.getRegSubInfoMapList(dbName,subInfoAllList);


        Map<String,LinkedHashMap<String,List<String>>> listMap = new LinkedHashMap<>();

        File file = new File("D:\\冷站项目部署\\佛山普立华替换程序相关\\更新历史库的数据副本.txt");
        FileWriter out = null;
        BufferedWriter bw = null;
        try {
            if(!file.exists()){
                file.createNewFile();
            }
            out = new FileWriter (file);
            bw = new BufferedWriter(out);

        for(QstagModbusTcp qsTagModbusTcp : rawList){
            count++;
            String pointName = qsTagModbusTcp.getPointName();//点位名称，中英文格式，如CHP2频率反馈
            String itemId = qsTagModbusTcp.getItemid();//寄存器地址,如40001
            String opt = qsTagModbusTcp.getOpt();
            if(!StringUtils.hasLength(pointName) || !StringUtils.hasLength(itemId)){
                continue;
            }

            Qstag qstag = new Qstag();
            long valueType = 1;//1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
            if(StringUtils.hasLength(qsTagModbusTcp.getDataType())){
                valueType = getValueType(qsTagModbusTcp.getDataType().trim().toUpperCase());
            }
            qstag.setValuetype(valueType);//值类型，从dataType转换而来,1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）

            long readType = 1;
            if(StringUtils.hasLength(qsTagModbusTcp.getReadWrite())){
                readType = getReadWriteType(qsTagModbusTcp.getReadWrite().trim().toUpperCase());
            }
            qstag.setItemreadtype(readType);//读写属性，1只读，2读写，3只写
            String ipAndPort = qsTagModbusTcp.getItemdrid();//格式如：192.168.10.20:502
            String port = ipAndPort.split(":")[1];
            String bit = StringUtils.hasLength(qsTagModbusTcp.getBit()) ? ( ":" + qsTagModbusTcp.getBit()) : "";
            String itemIdName = port + "-" + itemId.trim() + bit;
            qstag.setTagname(FormatUtil.getCharAndNumber(pointName.trim()) + itemIdName);//变量寄存器名称,根据寄存器地址生成
            qstag.setTagnameCN(pointName.trim());//变量中文名称
            qstag.setTagvalue("0");//
            qstag.setTagdesc(qsTagModbusTcp.getTagdesc());
            qstag.setUnits(qsTagModbusTcp.getUnits());
            qstag.setGroupName(qsTagModbusTcp.getGroupName());
            qstag.setTagvartype(1L);//点位类型，变量数据来源 设备还是公式。或变量类型： 1表示采集变量，值由驱动从设备或者第三方接口产生；2表示内存变量，由采集变量根据计算公式得到。
            qstag.setItemid(itemIdName);//通讯变量寄存器地址
            qstag.setItemdradd(qsTagModbusTcp.getItemdradd().trim());//设备地址，modbus的从站编号
            String itemXs = qsTagModbusTcp.getItemxs();
            itemXs = !StringUtils.hasLength(itemXs) ? "1" : itemXs.trim();
            qstag.setItemxs(FormatUtil.getNumber(itemXs));//系数
            String controlLevel = qsTagModbusTcp.getControlLevel();
            qstag.setControl(StringUtils.hasLength(controlLevel) ? Long.parseLong(controlLevel) : 0L);
            String meteringGroup = qsTagModbusTcp.getMeteringGroup();
            qstag.setMeteringGroup(StringUtils.hasLength(meteringGroup) ? meteringGroup : null);

            Qstag oldQsTag = null;
            List<Qstag> tempList = qsTagMap.get(itemIdName);//111111111111111111111111111111111111111111
            //List<Qstag> tempList = qsTagMap.get(pointName.trim());
            if(tempList != null && tempList.size() > 0){
                oldQsTag = tempList.get(0);
            }


            String subIdKey = subinfoService.getSubInfoKey(qstag.getTagdesc());
            Long subId = regSubInfoMap.get(subIdKey);
            String tempSubId = null;
            if(subId == null){
            }else{
                tempSubId = String.valueOf(subId);//设置需要显示的回显字符
            }

            String itemdrid = "NULL";
            if(oldQsTag == null){
                System.out.println("新增点位，序号：" + count + "，名称：" + pointName.trim() + "，数据类型：" + qsTagModbusTcp.getDataType().trim().toUpperCase() + "，端口-modbus地址：" + itemIdName + "，读写类型：" + qsTagModbusTcp.getReadWrite().trim().toUpperCase()+ "，系数：" + qsTagModbusTcp.getItemxs().trim());
                //INSERT INTO `qstag` (`tagname`, `tagnameCN`, `tagvalue`, `valuetype`, `itemdrid`, `itemtype`, `itemid`, `itemdradd`, `itemreadtype`, `itemxs`, `savetime`, `backtime`, `updatetime`, `units`, `tagdesc`, `tagvartype`, `tagformula`)
                //VALUES ('SY-502-41217', 'SY冷塔趋近度最终设定值', '22.0', 5, 1, NULL, '502-41217', '1', 1, '1', '5', '2023-05-09 08:35:02', '2023-05-09 08:35:04', '℃', '℃', 1, NULL);
                String addSql1 = "INSERT INTO `qstag` (`tagname`, `tagnameCN`, `tagvalue`, `valuetype`, `itemdrid`, `itemtype`, `itemid`, `itemdradd`, `itemreadtype`, `itemxs`, `savetime`, `backtime`, `updatetime`, `units`, `tagdesc`, `tagvartype`, `tagformula`) ";
                String addSql2 = "VALUES ('" + qstag.getTagname() + "', '" + pointName.trim() + "', '0', " + valueType + ", " + itemdrid + ", NULL, '" + itemIdName + "', '1', " + qstag.getItemreadtype() + " , '" + qstag.getItemxs() + "', '5', NULL, NULL, '" + qstag.getUnits() + "', '" + qstag.getTagdesc() + "', 1, NULL);";
                //System.out.println(addSql1 + addSql2);
            }else{
                String mess = "序号：" + count + ",端口-modbus地址:" + itemIdName;
                String mess2 = "";

                Long regGroupId = 1L;
                RegGroup regGroup = groupMap.get(qsTagModbusTcp.getGroupName());
                if(regGroup != null){
                    regGroupId = regGroup.getId();
                    String updateSqlGroup = "UPDATE reg SET reg_group_id =" + regGroup.getId() + " WHERE tag_name = '" + oldQsTag.getTagname() + "';";
                    //System.out.println(updateSqlGroup);
                }

                //String updateSqlGroup = "UPDATE qstag SET control =" + qstag.getControl() + " WHERE itemid = '" + oldQsTag.getItemid() + "';";
                //System.out.println(updateSqlGroup);

                if(qstag.getMeteringGroup() != null){
                    String updateSqlGroup = "UPDATE qstag SET meteringGroup ='" + qstag.getMeteringGroup() + "' WHERE itemid = '" + oldQsTag.getItemid() + "';";
                    //System.out.println(updateSqlGroup);
                }

                if(!qstag.getTagname().equals(oldQsTag.getTagname())){
                    mess2 = mess2 + "，Tagname不同，old Tagname：" + oldQsTag.getTagname() + "，new Tagname：" + qstag.getTagname() + "；";

                    //reg_value_half_hour表
                    String updateHalfHourSql = "UPDATE reg_value_half_hour SET tag_name ='" + qstag.getTagname() + "' WHERE tag_name = '" + oldQsTag.getTagname() + "';";
                    //System.out.println(updateHalfHourSql);

                    //reg_value_one_hour表
                    String updateOneHourSql = "UPDATE reg_value_one_hour SET tag_name ='" + qstag.getTagname() + "' WHERE tag_name = '" + oldQsTag.getTagname() + "';";
                    //System.out.println(updateOneHourSql);

                    //reg_value_ten_min表
                    String updateTenMinSql = "UPDATE reg_value_ten_min SET tag_name ='" + qstag.getTagname() + "' WHERE tag_name = '" + oldQsTag.getTagname() + "';";
                    //System.out.println(updateTenMinSql);

                    //tagdata_历史库表
                    DateTime startTime = DateUtil.parse("2022-05-11");
                    DateTime currentTime = DateUtil.date();//统计时间
                    String[] yearMonths1 = {"2022-05-01 00:00:00","2022-06-01 00:00:00","2022-07-01 00:00:00","2022-08-01 00:00:00","2022-09-01 00:00:00","2022-10-01 00:00:00","2022-11-01 00:00:00","2022-12-01 00:00:00","2023-01-01 00:00:00","2023-02-01 00:00:00","2023-03-01 00:00:00","2023-04-01 00:00:00","2023-05-01 00:00:00"};

                    for(String currentMonth : yearMonths1){
                        String tempMonth = currentMonth.substring(0,7);//如2023-04
                        int daysByYearMonth = MyDateUtils.getDaysByYearMonthStr(currentMonth,"yyyy-MM");//获取当月一共有几天
                        String[] dayOfMonthArray = new String[daysByYearMonth];//存储当天24小时的时间，如2023-03-13 00:00:00,2023-03-13 01:00:00，，2023-03-13 23:00:00
                        for(int i=1;i<=daysByYearMonth;i++){
                            String day = i < 10 ? "0" + i : "" + i;
                            String currentDay = tempMonth + "-" + day;
                            dayOfMonthArray[i-1] = currentDay;
                        }

                        LinkedHashMap<String,List<String>> tempMonthSqlMap = listMap.computeIfAbsent(currentMonth, k -> new LinkedHashMap<>());

                        for(String currentDay : dayOfMonthArray){
                            DateTime dayTime = DateUtil.parse(currentDay);
                            if(dayTime.isBefore(startTime)){
                                //不上报当前时间之后的数据，因为时间还没到,数据不存在
                                //log.debug("不更新2022-05-11之前的数据，因为时间从2022-05-11开始。打算上报时间：{}，开始时间：{}",dayTime,startTime);
                                continue;
                            }
                            if(dayTime.isAfter(currentTime)){
                                //不上报当前时间之后的数据，因为时间还没到,数据不存在
                                //log.debug("不上报当前时间之后的数据，因为时间还没到,数据不存在。打算上报时间：{}，当前时间：{}",dayTime,currentTime);
                                break;
                            }

                            //上报每一天的
                            String dataBase = dbName + "_data";//项目历史数据库
                            String tagDataTableName = "tagdata_" + sdf1.format(dayTime);

                            String updateDataSql = "UPDATE " + tagDataTableName + " SET tagname ='" + qstag.getTagname() + "' WHERE tagname = '" + oldQsTag.getTagname() + "';";
                            //System.out.println(updateDataSql);

                            List<String> tempDaySqlList = tempMonthSqlMap.computeIfAbsent(currentDay, k -> new ArrayList<>());
                            tempDaySqlList.add(updateDataSql);

                        }
                    }

                    //qstag表   t.itemxs = '" + qstag.getItemxs() + "',
                    String updateQsTagSql1 = "UPDATE qstag t SET t.tagname = '" + qstag.getTagname() + "', t.valuetype = " + valueType + ", t.itemdrid = " + itemdrid + ", t.itemtype = NULL,t.itemid = '" + itemIdName + "', t.itemdradd = '1', ";//
                    String updateQsTagSql2 = "t.itemreadtype = " + qstag.getItemreadtype() + ", t.units = '" + qstag.getUnits() + "', t.tagdesc = '" + qstag.getTagdesc() + "', t.tagvartype = 1 WHERE t.tagname = '" + oldQsTag.getTagname() + "';";//
                    //System.out.println(updateQsTagSql1 + updateQsTagSql2);

                    //reg表
                    String updateRegSql1 = "UPDATE reg t SET t.tag_name = '" + qstag.getTagname() + "', t.reg_Type = '" + valueType + "', t.reg_Units = '" + qstag.getUnits() + "', t.reg_ReadWrite = '" + qstag.getItemreadtype() + "', ";//
                    String updateRegSql2 = "t.reg_group_id = " + regGroupId + ", t.reg_sub = '" + tempSubId + "', t.is_threeD_show = 1, t.Ishistory = '1', t.tag_alarm_state = '0' WHERE t.tag_name = '" + oldQsTag.getTagname() + "';";//
                    //System.out.println(updateRegSql1 + updateRegSql2);

                }
                if(!qstag.getTagnameCN().equals(oldQsTag.getTagnameCN())){
                    mess2 = mess2 + "，中文名称不同，旧名称：" + oldQsTag.getTagnameCN() + "，新名称：" + qstag.getTagnameCN() + "；";
                }
                if(!qstag.getValuetype().equals(oldQsTag.getValuetype())){
                    mess2 = mess2 + "，数据类型不同，旧数据类型：" + oldQsTag.getValuetype() + "，新数据类型：" + qstag.getValuetype() + "；";
                }
                if(!qstag.getItemreadtype().equals(oldQsTag.getItemreadtype())){
                    String tempOldReadType = "";//读写属性，1只读，2读写，3只写
                    if(oldQsTag.getItemreadtype() == 1){
                        tempOldReadType = "R";
                    }else if(oldQsTag.getItemreadtype() == 2){
                        tempOldReadType = "RW";
                    }else if(oldQsTag.getItemreadtype() == 3){
                        tempOldReadType = "W";
                    }
                    String tempReadType = "";
                    if(qstag.getItemreadtype() == 1){
                        tempReadType = "R";
                    }else if(qstag.getItemreadtype() == 2){
                        tempReadType = "RW";
                    }else if(qstag.getItemreadtype() == 3){
                        tempReadType = "W";
                    }
                    mess2 = mess2 + "，读写类型不同，旧类型：" + tempOldReadType + "，新类型：" + tempReadType + "；";
                    String updateSql = "UPDATE qstag SET itemreadtype=" + qstag.getItemreadtype() + " WHERE itemid = '" + itemIdName + "' AND itemreadtype=" + oldQsTag.getItemreadtype() + ";";
                    //System.out.println(updateSql);
                }
                if(!qstag.getItemxs().equals(oldQsTag.getItemxs())){
                    mess2 = mess2 + "，系数不同，旧系数：" + oldQsTag.getItemxs() + "，新系数：" + qstag.getItemxs() + "；";
                    String updateSql = "UPDATE qstag SET itemxs='" + qstag.getItemxs() + "' WHERE itemid = '" + itemIdName + "' AND tagname='" + oldQsTag.getTagname() + "';";
                    //System.out.println(updateSql);
                }
                if(StringUtils.hasLength(mess2)){
                    System.out.println(mess + mess2);
                }
            }
        }

            listMap.keySet();
            Iterator iterator = listMap.keySet().iterator();
            while (iterator.hasNext()){
                String currentMonth = (String)iterator.next();
                LinkedHashMap<String,List<String>> tempMonthSqlMap = listMap.get(currentMonth);
                if(tempMonthSqlMap != null){
                    Iterator iteratorDay = tempMonthSqlMap.keySet().iterator();
                    while (iteratorDay.hasNext()){
                        String currentDay = (String)iteratorDay.next();
                        List<String> sqlList = tempMonthSqlMap.get(currentDay);
                        for(String updateDataSql : sqlList){
                            /*bw.write(updateDataSql);
                            bw.newLine();*/
                        }
                        /*bw.newLine();
                        bw.newLine();
                        bw.write("###================================================================================================================================================================================================###");
                        bw.newLine();
                        bw.write("###================================================================================================================================================================================================###");
                        bw.newLine();
                        bw.write("###================================================================================================================================================================================================###");
                        bw.newLine();
                        bw.newLine();
                        bw.newLine();*/
                    }
                }
                /*bw.newLine();
                bw.newLine();
                bw.write("#####################################################################################################################################################################################################################");
                bw.newLine();
                bw.write("#####################################################################################################################################################################################################################");
                bw.newLine();
                bw.write("#####################################################################################################################################################################################################################");
                bw.newLine();
                bw.write("#####################################################################################################################################################################################################################");
                bw.newLine();
                bw.write("#####################################################################################################################################################################################################################");
                bw.newLine();
                bw.newLine();*/

            }

            bw.flush();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            /*if(bw != null){
                try{
                    bw.flush();
                    bw.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }*/
        }

        return AjaxResult.success("DEV环境检查数据差异，直接返回");
    }

    public static void main(String[] args) {
        /*String pointName = "CWP4硬件报警";
        String prefix = FormatUtil.getCharAndNumber(pointName);
        System.out.println(prefix);
        if(pointName.contains(":")){
            //如pointName=KT:BGS02风速模式，则prefix=KT-BGS02-
            if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                String tempDrCode = prefix.substring(prefix.indexOf("-") + 1);//得到第一个“-”符号后面的字符串
                if(StringUtils.hasLength(tempDrCode) && tempDrCode.contains("-")){
                    String drCode = tempDrCode.substring(0,tempDrCode.indexOf("-"));
                    System.out.println("11 " + drCode);
                }
                prefix = prefix.substring(0,prefix.indexOf("-"));//最终格式如：CWP4
                System.out.println("12 " + prefix);
            }
        }else{
            if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                prefix = prefix.substring(0,prefix.indexOf("-"));//最终格式如：CWP4
                String drCode = prefix;//设备编码格式如：CWP4
                System.out.println("13 " + prefix);
                System.out.println("14 " + drCode);
            }
        }*/

        //pointNameKey包含CT的有CT11,CT12,CTF11,CTF12,CT1,CT2等等
        String number = FormatUtil.getNumber("CT11");
        System.out.println(number);
        String number2 = FormatUtil.getNumber("CT12");
        System.out.println(number2);
        String number3 = FormatUtil.getNumber("CTF11");
        System.out.println(number3);
        String number4 = FormatUtil.getNumber("CT1");
        System.out.println(number4);
        String number5 = FormatUtil.getNumber("CT2");
        System.out.println(number5);
        String name = "CTF35";
        String number6 = FormatUtil.getNumber(name);
        System.out.println(number6);
        String dd = name.substring(0,name.indexOf(number6));
        System.out.println(dd);
    }

    private AjaxResult checkAndCreateDrTypeMode(String dbName,List<QstagModbusTcp> rawList,Map<String,String> drTypeCodeMap){
        try{
            TreeSet<String> drCodeSet = new TreeSet<>();//存储每一项点位名称的编码，使用集合去重，如点位名称列的值为：CWP4硬件报警、CHP1远程，等等，那么存储的是前缀的CWP4、CHP1
            TreeSet<String> drTypeCodeSet = new TreeSet<>();//存储的是设备类型编码，如点位名称列的值为：CWP4硬件报警、CHP1远程，则提取出：CWP、CHP，表示分别属于设备类型CWP、CHP。这里存储的就是CWP、CHP这些。最终可能有：CHP、CWP、FCH、HCH、HWP、LCH、MCH、RHH、RHT、CT、DV、EC、HT、QX、SY、P、T、V
            LinkedHashMap<String,QstagModbusTcp> pointNameRawMap = new LinkedHashMap<>();//根据点位名称存储的Map，里面的值后面的处理程序会动态修改（删除）
            Map<String,LinkedHashSet<String>> drTypeCodeRegNameMap = new HashMap<>();//以设备类型编码drTypeCode为key存储设备类型模板属性，如“CWP4硬件报警”、“CWP4运行报警”、“CHP1远程”、“CHP1电压”，提取到“（CWP,[硬件报警,运行报警]）”、“（CHP,[远程,电压]）”
            TreeSet<String> groupRawList = new TreeSet<>();
            for(QstagModbusTcp qsTagModbusTcp : rawList){
                String pointName = qsTagModbusTcp.getPointName();//点位名称，如CWP4硬件报警
                //String dataType = qsTagModbusTcp.getDataType();//如BOOL、REAL、INT这些
                if(!StringUtils.hasLength(pointName)){
                    continue;//过滤掉控名称的行
                }
                String groupName = qsTagModbusTcp.getGroupName();
                if(StringUtils.hasLength(groupName)){
                    groupRawList.add(groupName.trim());
                }
                pointNameRawMap.put(pointName,qsTagModbusTcp);//先存储，后面处理使用，格式为（CWP4硬件报警，对应的点表行信息）
                String prefix = FormatUtil.getCharAndNumber(pointName);//找到点位名称中的所有非中文字符，如 CWP4硬件报警，则得到CWP4-，如pointName=KT:BGS02风速模式，则prefix=KT-BGS02-
                String drCode = "";
                String drTypeCode = "";
                if(pointName.contains(":")){
                    //如pointName=KT:BGS02风速模式，则prefix=KT-BGS02-
                    if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                        String tempDrCode = prefix.substring(prefix.indexOf("-") + 1);//得到第一个“-”符号后面的字符串
                        if(StringUtils.hasLength(tempDrCode) && tempDrCode.contains("-")){
                            drCode = tempDrCode.substring(0,tempDrCode.indexOf("-"));//如prefix=KT-BGS02-，则最终drCode=BGS02
                        }
                        prefix = prefix.substring(0,prefix.indexOf("-"));//如prefix=KT-BGS02-，则最终prefix=KT
                    }
                }else{
                    if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                        prefix = prefix.substring(0,prefix.indexOf("-"));//如prefix=CWP4-，则最终prefix=CWP4
                        drCode = prefix;//如prefix=CWP4-，则最终drCode=CWP4
                    }
                }
                if(StringUtils.hasLength(drCode)){
                    drCodeSet.add(drCode);//存储如CWP4、CHP1、CWP2、CHP3...
                }
                String number = FormatUtil.getNumber(prefix);//prefix格式可能有CWP4，也可能有KT，多数情况下是CWP4，就是带数字编号的这种格式。
                if(StringUtils.hasLength(number)){
                    prefix = prefix.substring(0,prefix.indexOf(number));
                }
                drTypeCode = prefix;//drTypeCode的最终格式就是去掉数字编号的 设备类型编码，如CWP
                if(StringUtils.hasLength(drTypeCode)){
                    drTypeCodeSet.add(drTypeCode);//消除重复记录
                }
            }
            if(drCodeSet.size() > 0){
                log.debug("提取到的设备编码有：");
                drCodeSet.forEach(System.out::println);//这样打印，可以拷贝出来放到设备清单excel列表中进行导入
            }
            List<String> drTypeCodeList = new ArrayList<>(drTypeCodeSet);
            if(drTypeCodeList.size() > 0){
                boolean find = false;
                for(String code : drTypeCodeList){
                    if("CTF".equals(code.toUpperCase())){
                        find = true;
                    }
                }
                if(!find){
                    drTypeCodeList.add("CTF");
                }
            }
            //排序设备类型编码，字符串长的排在前面
            Collections.sort(drTypeCodeList, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    if(o2.length() == o1.length()){
                        return o1.compareTo(o2);
                    }else{
                        return o2.length() - o1.length();
                    }
                }
            });

            Map<String,List<Drtypeinfo>> drTypeInfoMap = new HashMap<>();//根据设备类型编码分组存储设备类型信息
            String zSqyDbName = centralDatabase;//去处理综合库
            List<Drtypeinfo> drTypeInfoList = drtypeinfoService.findAllDrtypeAndDrReturnList(zSqyDbName,0);//检查综合库的drtypeinfo表，通常有值返回
            if(drTypeInfoList != null){
                drTypeInfoMap = drTypeInfoList.stream().filter(drTypeInfo -> StringUtils.hasLength(drTypeInfo.getDrTypeCode())).collect(Collectors.groupingBy(Drtypeinfo::getDrTypeCode));
            }

            Map<Long,List<Drtypemode>> drTypeAllModeMap = new HashMap<>();//根据设备类型ID分组存储设备属性信息
            List<Drtypemode> drTypeAllModeList = drtypemodeMapper.findAllModeList(dbName);//检查项目库的drtypemode表，不一定有值返回
            if(drTypeAllModeList != null){
                drTypeAllModeMap = drTypeAllModeList.stream().collect(Collectors.groupingBy(Drtypemode::getDrtypeid));
            }

            //检查中心库.drtypeinfo表设备类型是否已经配置
            boolean find = false;
            String errorDrTypeCode = null;
            //遍历设备类型编码
            for(String drTypeCode : drTypeCodeList){
                List<Drtypeinfo> list = drTypeInfoMap.get(drTypeCode);//综合库中根据设备类型编码返回设备类型信息
                if(list != null && list.size() > 0){
                    find = true;//找到
                }
                if(!find){
                    //如果没有找到，提示先设置模型类型，只需在综合库中心库的drtypeinfo表中添加设备类型
                    errorDrTypeCode = drTypeCode;
                    break;
                }
            }
            if(!find){
                return AjaxResult.error(50009,"设备类型" + errorDrTypeCode + "不存在，先添加设备类型");
            }

            //先处理分组
            //检查项目库.reg_group表分组，模板里面需要分组
            long maxGroupId = 0L;
            List<RegGroup> regGroupList = regGroupMapper.findAllRegGroup(dbName);//
            Map<String,RegGroup> regGroupMap = new HashMap<>();
            if(regGroupList != null && regGroupList.size() > 0){
                for(RegGroup regGroup : regGroupList){
                    regGroupMap.put(regGroup.getGroupName(),regGroup);
                    long tempGroupId = regGroup.getId();
                    if(tempGroupId > maxGroupId){
                        maxGroupId = tempGroupId;
                    }
                }
            }
            long sorted = maxGroupId + 1L;
            for(String groupName : groupRawList){
                //插入或更新分组
                RegGroup tempRegGroup = regGroupMap.get(groupName);
                if(tempRegGroup == null){
                    //插入
                    tempRegGroup = new RegGroup();
                    tempRegGroup.setGroupName(groupName);
                    tempRegGroup.setSorted(sorted);
                    tempRegGroup.setDrtypeid(75L);
                    regGroupMapper.insertRegGroupNameWithoutId(dbName,tempRegGroup);
                    sorted++;
                }else{
                    //不做处理
                }
            }
            regGroupList = regGroupMapper.findAllRegGroup(dbName);//重新加载一次
            if(regGroupList != null){
                regGroupList.forEach(regGroup -> {
                    regGroupMap.put(regGroup.getGroupName(),regGroup);
                });
            }

            List<Subinfo> subInfoAllList = subinfoService.findAllObject(dbName);//查询项目的设备属性数据回显，项目的subinfo表
            Map<String,Long> regSubInfoMap = subinfoService.getRegSubInfoMapList(dbName,subInfoAllList);//构造数据结构后面使用

            Map<String,String> tempTypeCodeRegNameMap = new HashMap<>();//存储设备类型编码+设备属性。如点位名称如“CWP4硬件报警”、“CWP4运行报警”、“CHP1远程”、“CHP1电压”，则存储“CWP硬件报警”、“CWP运行报警”、“CHP远程”、“CHP电压”，没有设备编号，只有设备类型编码
            //遍历所有设备类型
            for(String drTypeCode : drTypeCodeList){
                String replaceDrTypeCode = drTypeCode;//有些地方用到drTypeCode，有些地方用到经过变换后的值
                Iterator<String> iterator = pointNameRawMap.keySet().iterator();
                while (iterator.hasNext()){
                    //找出点表中所有以drTypeCode开头的项
                    String pointNameKey = (String)iterator.next();//如CH1运行，
                    if(pointNameKey.contains(drTypeCode)){//drTypeCode如CH，则“CH1运行”包含“CH”
                        String prefix = FormatUtil.getCharAndNumber(pointNameKey);//找到点位名称中的所有非中文字符，如 CWP4硬件报警，则得到CWP4-，如pointName=KT:BGS02风速模式，则prefix=KT-BGS02-
                        if(pointNameKey.contains(":")){
                            if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                                prefix = prefix.substring(0,prefix.lastIndexOf("-"));//这里可能得到KT-BGS02
                            }
                        }else{
                            if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                                prefix = prefix.substring(0,prefix.indexOf("-"));//这里可能得到 CWP4
                            }
                        }

                        String regNameCN = pointNameKey.substring(prefix.length());//格式pointNameKey = CWP4硬件报警，则得到prefix=CWP4，最终regNameCN=硬件报警。如果pointNameKey = KT:BGS02风速模式，则得到prefix=KT-BGS02，最终regNameCN=风速模式
                        if(regNameCN.contains("-") && regNameCN.startsWith("-")){
                            regNameCN = regNameCN.substring(1);
                        }
                        if(pointNameKey.contains("CT")){
                            //pointNameKey包含CT的有CT11,CT12,CTF11,CTF12,CT1,CT2等等
                            String number = FormatUtil.getNumber(pointNameKey);
                            int numberInt = 0;
                            try{
                                numberInt = Integer.parseInt(number);
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                            String tempDrTypeCode = pointNameKey.substring(0,pointNameKey.indexOf(number));
                            if(prefix.contains("CT") && numberInt > 10){
                                //处理CT11、CT12、CT21、CT24、CT31、CTF11、CTF12,等等 都当成CTF来处理，即冷却塔风机
                                replaceDrTypeCode = "CTF";
                            }else{
                                //drTypeCode -> CT，处理CT1、CT2、CT3、CT4、CT5、CT6、CT7、CT8、CT9、CT10，当冷却塔组来处理
                                if(StringUtils.hasLength(tempDrTypeCode) && "CT".equals(tempDrTypeCode.toUpperCase())){
                                    replaceDrTypeCode = "CT";
                                }else{
                                    replaceDrTypeCode = drTypeCode;//恢复为drTypeCode
                                }
                            }
                        }

                        //将点表和设备类型对应并存储起来
                        if(pointNameKey.contains(":")){
                            drTypeCodeMap.put(pointNameKey.substring(pointNameKey.indexOf(":") + 1),replaceDrTypeCode);//存储（点位名称，设备类型编码）格式的数据
                        }else{
                            drTypeCodeMap.put(pointNameKey,replaceDrTypeCode);//存储（点位名称，设备类型编码）格式的数据
                        }

                        LinkedHashSet<String> regNameCNList = drTypeCodeRegNameMap.computeIfAbsent(replaceDrTypeCode, k -> new LinkedHashSet<>());//以drTypeCode开头的项存在多个，用一个属性列表存储
                        QstagModbusTcp qstagModbusTcp = pointNameRawMap.get(pointNameKey);
                        String dataType = qstagModbusTcp.getDataType();
                        String readWrite = qstagModbusTcp.getReadWrite();
                        String tagDesc = qstagModbusTcp.getTagdesc();
                        String units = qstagModbusTcp.getUnits();
                        String groupName = qstagModbusTcp.getGroupName();
                        String alarmLevel = qstagModbusTcp.getAlarmLevel();
                        String key = replaceDrTypeCode + regNameCN;//去重
                        String keyValue = tempTypeCodeRegNameMap.get(key);
                        if(keyValue == null){
                            regNameCNList.add(regNameCN + "|" + dataType + "|" + readWrite + "|" + tagDesc + "|" + units + "|" + groupName + "|" + alarmLevel);
                            tempTypeCodeRegNameMap.put(key,key);
                        }
                        iterator.remove();//找完之后清除该项
                    }
                }

                //检查某个设备类型的所有属性名称
                LinkedHashSet<String> regNameCNList = drTypeCodeRegNameMap.get(replaceDrTypeCode);
                handlerDrTypeMode(dbName,replaceDrTypeCode,regNameCNList,drTypeInfoList,regSubInfoMap,regGroupMap,drTypeAllModeMap);
                if(replaceDrTypeCode.contains("CT")){
                    //如果是包含CT，再执行一次，防止漏掉某些属性CT，CT转CTF的问题导致。后面点表统一使用CTF作为冷却的风机，CT作为冷却塔组即可不必这么执行。
                    String handerDrCode = replaceDrTypeCode;
                    if("CTF".equals(replaceDrTypeCode)){
                        handerDrCode = "CT";
                    }else if("CT".equals(replaceDrTypeCode)){
                        handerDrCode = "CTF";
                    }
                    regNameCNList = drTypeCodeRegNameMap.get(handerDrCode);
                    handlerDrTypeMode(dbName,handerDrCode,regNameCNList,drTypeInfoList,regSubInfoMap,regGroupMap,drTypeAllModeMap);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("checkAndCreateDrTypeMode Exception",e);
            return AjaxResult.error(50009, "保存失败");
        }
        return null;//正常时候返回NULL
    }

    private void handlerDrTypeMode(String dbName,String replaceDrTypeCode,LinkedHashSet<String> regNameCNList,List<Drtypeinfo> drTypeInfoList,Map<String,Long> regSubInfoMap,Map<String,RegGroup> regGroupMap,Map<Long,List<Drtypemode>> drTypeAllModeMap){
        if(regNameCNList != null && regNameCNList.size() > 0){
            Long drTypeId = 0L;
            for(Drtypeinfo drTypeInfo : drTypeInfoList){
                String tempDrTypeCode = drTypeInfo.getDrTypeCode();
                String currentDrTypeCode = replaceDrTypeCode;
                if("V".equals(replaceDrTypeCode)){
                    currentDrTypeCode = "VM";//调节阀
                }else if("DV".equals(replaceDrTypeCode)){
                    currentDrTypeCode = "FM";//调节阀
                }
                if(StringUtils.hasLength(tempDrTypeCode) && currentDrTypeCode.equals(tempDrTypeCode)){
                    drTypeId = drTypeInfo.getDrtypeid();//找到drTypeCode设备类型编码所对应的设备类型对象ID，后面用到
                    break;
                }
            }
            if(drTypeId == 0){
                return;
            }
            boolean isNull = false;
            List<Drtypemode> drTypeModeList = drTypeAllModeMap.get(drTypeId);//检查项目库的drtypemode表
            if(drTypeModeList == null || drTypeModeList.size() == 0){
                isNull = true;//该设备类型drTypeCode对应的模板属性还没有，直接添加到项目表中（非综合库中）
            }
            for(String tempRegNameCN : regNameCNList){
                //regNameCN + "|" + dataType + "|" + readWrite + "|" + tagDesc + "|" + units
                String[] array = tempRegNameCN.split("\\|");
                String regNameCN = array[0];
                String dataType = array[1];
                String readWrite = array[2];
                String tagDesc = array[3];
                String units = array[4];//
                String groupName = array[5];//
                String alarmLevel = array[6];//

                Long typeModeId = null;
                boolean needAdd = true;//假设需要添加，初始值一定要是true
                if(isNull){
                    //全部没有，则全部添加
                    needAdd = true;
                }else{
                    //项目库中存在这些属性，需要检查
                    for(Drtypemode tempDrTypeMode : drTypeModeList){
                        String regName = tempDrTypeMode.getRegName();
                        if(StringUtils.hasLength(regName) && regName.equals(regNameCN.trim())){
                            //找到，不需要添加，但需要更新
                            needAdd = false;
                            typeModeId = tempDrTypeMode.getTypemodeid();
                            break;
                        }
                    }
                }

                //先制作数据
                Drtypemode drtypemode = new Drtypemode();
                drtypemode.setDrtypeid(drTypeId);
                drtypemode.setRegName(regNameCN.trim());
                drtypemode.setRegType(String.valueOf(getValueType(dataType.trim().toUpperCase())));//dataType 寄存器类型（7种类型固定：1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
                if(StringUtils.hasLength(units) && !"NULL".equals(units.toUpperCase())){
                    drtypemode.setRegUnits(units);
                }
                drtypemode.setRegReadwrite(String.valueOf(getReadWriteType(readWrite.trim().toUpperCase())));//读写属性（３种类型：1只读、2读写、3只写）
                drtypemode.setTagValue("0");
                long regListShowLevel = 2L;
                if(regNameCN.trim().contains("电量")){/* || regNameCN.trim().endsWith("热量") || regNameCN.trim().endsWith("冷量")*/
                    regListShowLevel = 1L;//先不处理热量和冷量，3D弹窗界面上没热量和冷量的tab页面，只有电量的
                }
                drtypemode.setRegListshowlevel(regListShowLevel);//电量需要是1,3D显示时候用1判断显示。

                String subIdKey = subinfoService.getSubInfoKey(tagDesc);
                Long subId = regSubInfoMap.get(subIdKey);
                if(subId == null){
                    String tempSubId = null;
                    if(StringUtils.hasLength(subIdKey)){
                        log.warn("阈值不存在，需要插入：{}",regNameCN + "(" + subIdKey + ")");
                        Sub sub = new Sub();
                        sub.setSubname(regNameCN + "(" + subIdKey + ")");
                        int rows = subService.insertObjectForGetSubId(dbName,sub);//往项目库
                        if(rows > 0){
                            regSubInfoMap.put(subIdKey,sub.getSubid());
                            tempSubId = String.valueOf(sub.getSubid());
                            List<Subinfo> subInfoList = subinfoService.getSubInfoFromSubIdKey(sub.getSubid(),subIdKey);
                            for(Subinfo subinfo : subInfoList){
                                subinfoService.saveObject(dbName,subinfo);
                            }
                        }
                    }
                    drtypemode.setRegSub(tempSubId);//默认是不设置RegSub，就是弹窗的”控制参数“中不显示下拉菜单控制按钮等，默认显示输入框，否则浮点数的值，不会出现输入框
                }else{
                    log.debug("更新数据回显:{}",regNameCN + "(" + subIdKey + ")");
                    drtypemode.setRegSub(String.valueOf(subId));//设置需要显示的回显字符
                    Sub sub = new Sub();
                    sub.setSubid(subId);
                    sub.setSubname(regNameCN + "(" + subIdKey + ")");
                    int row = subService.updateObject(dbName,sub);//更新项目库sub的回显名称
                    if(row > 0){
                        List<Subinfo> subInfoList = subinfoService.getSubInfoFromSubIdKey(subId,subIdKey);
                        for(Subinfo subinfo : subInfoList){
                            subinfoService.updateObjectBySubIdAndValue(dbName,subinfo);
                        }
                    }
                }

                //关于报警，检查点表中 “报警等级” 参数：
                // 0不是报警，1一般报警；2.严重报警；3.紧急报警；一般等级就弹窗一次，严重的等级就得播放声音，弹窗，紧急报警要做到微信推送，弹窗，浏览器播放声音
                // 冰机故障算紧急报警，水泵冷却塔报警算严重报警，风柜，传感器的报警算一般报警
                String regDrShowType = null;
                String isAlarm = null;
                String newAlarmLevel = "0";
                if(regNameCN.trim().equals("运行") || regNameCN.trim().equals("运行状态")){
                    regDrShowType = "1";
                }else if(regNameCN.trim().equals("运行报警") || regNameCN.trim().equals("硬件报警") || regNameCN.trim().equals("综合报警") || regNameCN.trim().equals("通讯报警")
                        || regNameCN.trim().equals("开报警") || regNameCN.trim().equals("关报警") || regNameCN.trim().equals("开异常") || regNameCN.trim().equals("关异常")
                        || regNameCN.trim().equals("高高报") || regNameCN.trim().equals("高报") || regNameCN.trim().equals("低低报") || regNameCN.trim().equals("低报")
                        || regNameCN.trim().contains("报警") || regNameCN.trim().contains("异常")){
                    regDrShowType = "2";
                    isAlarm = "1";
                    if(StringUtils.hasLength(alarmLevel)){
                        //关于报警，检查点表中 “报警等级” 参数：
                        // 0不是报警，1一般报警；2.严重报警；3.紧急报警；一般等级就弹窗一次，严重的等级就得播放声音，弹窗，紧急报警要做到微信推送，弹窗，浏览器播放声音
                        // 冰机故障算紧急报警，水泵冷却塔报警算严重报警，风柜，传感器的报警算一般报警
                        newAlarmLevel = alarmLevel;
                    }
                }else if(regNameCN.trim().equals("设备故障") || regNameCN.trim().equals("故障") || regNameCN.trim().equals("故障状态")){
                    regDrShowType = "3";
                }
                drtypemode.setRegDrshowtype(regDrShowType);//运行1，报警2，故障3。设备显示类型（设备属性），1运行点位（正常），2报警点位，3故障点位
                drtypemode.setIsalarm(isAlarm);
                drtypemode.setAlarmLevel(newAlarmLevel);
                RegGroup regGroup = regGroupMap.get(groupName);//项目库.reg_group表分组
                if(regGroup != null){
                    drtypemode.setRegGroupId(regGroup.getId());
                }else{
                    log.warn("分组名称：{}不存在项目库:{}.reg_group表中",groupName,dbName);
                    //应该不存在这种情况，因为前面已经获得点表的所有分组，并且已经提前插入或更新了项目库的reg_group表了
                    Long groupId = 1L;
                    if(StringUtils.hasLength(groupName) && !"null".equals(groupName.toLowerCase())){
                        RegGroup tempRegGroup = new RegGroup();
                        tempRegGroup.setGroupName(groupName);
                        tempRegGroup.setSorted(50L);
                        tempRegGroup.setDrtypeid(75L);
                        int rows = regGroupMapper.insertDrTypeModeGroupName(dbName,tempRegGroup);//往项目库中插入分组，防止主键冲突异常
                        if(rows > 0){
                            groupId = tempRegGroup.getId();
                        }
                    }
                    drtypemode.setRegGroupId(groupId);
                }
                drtypemode.setIshistory("1");
                String isEnergy = null;
                if(regNameCN.trim().endsWith("电量") || regNameCN.trim().endsWith("热量") || regNameCN.trim().endsWith("冷量") || regNameCN.trim().endsWith("流量")){
                    isEnergy = "1";
                }
                drtypemode.setIsenergy(isEnergy);
                drtypemode.setIslistshow("1");
                drtypemode.setTagTime("5");

                //判断是新增还是更新
                if(needAdd){
                    int row = drtypemodeMapper.insertObject(dbName, drtypemode);//操作项目库的drtypemode表，就是设备属性表
                    if(row == 1){
                        typeModeId = drtypemode.getTypemodeid();
                        List<Drtypemode> tempList = drTypeAllModeMap.computeIfAbsent(drTypeId, k -> new ArrayList<>());
                        tempList.add(drtypemode);
                    }
                }else{
                    //更新
                    drtypemode.setTypemodeid(typeModeId);
                    drtypemodeMapper.updateObject(dbName,drtypemode);//操作项目库
                }
            }
        }
    }

    private long getValueType(String dataType){
        long valueType = 1L;//1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
        if("BOOL".equals(dataType.toUpperCase().trim())){
            valueType = 1L;//布尔型、离散型
        }else if("DINT".equals(dataType.toUpperCase().trim())){
            valueType = 2L;//长整型
        }else if("INT".equals(dataType.toUpperCase().trim())){
            valueType = 3L;//整型（先用长整型来读，看是否出错）
        }else if("DWORD".equals(dataType.toUpperCase().trim())){
            valueType = 7L;//型
        }else if("WORD".equals(dataType.toUpperCase().trim())){
            valueType = 4L;//型（先用型来读，看是否出错）
        }else if("REAL".equals(dataType.toUpperCase().trim())){
            valueType = 5L;//浮点型
        }else if("LREAL".equals(dataType.toUpperCase().trim())){
            valueType = 6L;//浮点型
        }
        return valueType;
    }

    private int getReadWriteType(String readWrite){
        int readType = 1;
        if("R".equals(readWrite) || "只读".equals(readWrite)){
            readType = 1;
        }else if("W".equals(readWrite) || "只写".equals(readWrite)){
            readType = 3;
        }else{
            readType = 2;
        }
        return readType;
    }

    /**
     * 导入ModbusTcp类型变量寄存器地址
     * @param dbName
     * @param rawList
     * @return
     */
    @Override
    public AjaxResult handlerImportModbusTcpExcel(String dbName,List<QstagModbusTcp> rawList) {
        if(!jobNeedStart){
            log.debug("DEV环境下，只是检查数据的异同，检查完毕后直接返回。");
            return checkTheDifferencesOfData(dbName,rawList);
        }

        Map<String,String> drTypeCodeMap = new HashMap<>();//存储点表名称和设备类型对应关系，（点位名称，设备类型编码）格式的数据

        AjaxResult checkResult = checkAndCreateDrTypeMode(dbName,rawList,drTypeCodeMap);//检查和创建设备类型模板、更新分组、更新阈值
        if(checkResult != null){
            return checkResult;//
        }

        List<Qstag> addList = new ArrayList<>();
        List<Qstag> deleteList = new ArrayList<>();

        //1、先导入param_type能耗类型配置中的统计变量（程序写死了根据这些变量进行查询）
        List<ParamType> paramTypeList = paramTypeService.findAll();//表：param_type（能耗类型配置表）
        if(!CollectionUtils.isEmpty(paramTypeList)){
            paramTypeList.forEach(paramType -> {
                String tagName = paramType.getTagName();//如：tagName：totalElectricity，regName：实时总电量
                if(StringUtils.hasLength(tagName)){
                    String regName = paramType.getRegName();
                    Qstag qstag = new Qstag();
                    qstag.setValuetype(5L);//5浮点型
                    qstag.setItemreadtype(1L);//读写属性，1只读，2读写，3只写
                    qstag.setTagname(tagName);//变量寄存器名称,根据寄存器地址生成
                    qstag.setTagnameCN(regName);//变量中文名称
                    qstag.setTagvalue("0");//初始值
                    qstag.setTagdesc(regName);
                    qstag.setTagvartype(1L);//点位类型，变量数据来源 设备还是公式。或变量类型： 1表示采集变量，值由驱动从设备或者第三方接口产生；2表示内存变量，由采集变量根据计算公式得到。
                    qstag.setItemid("local");//通讯变量寄存器地址
                    qstag.setItemdrid(0L);//先设置为0，需要在界面修改设置。通讯设备ID，见项目“设备采集管理”“设备采集配置”菜单界面设备采集配置列表的“设备ID”
                    qstag.setItemdradd("1");//设备地址，modbus的从站编号，好像没那么重要，经过测试，modbus tcp传的这个参数好像都可以，但是要传。
                    qstag.setItemxs("1");//系数
                    qstag.setSavetime("5");//默认5分钟存储
                    qstag.setBoolType(0L);
                    qstag.setAlarmtag(0L);
                    qstag.setAlarmforbid(1L);
                    qstag.setAlarmlevel(0L);
                    qstag.setAlarmdelay(30L);
                    qstag.setHhValue("0");
                    qstag.setHhAlarmLevel(0L);
                    qstag.setHvalue("0");
                    qstag.setHalarmLevel(0L);
                    qstag.setLvalue("0");
                    qstag.setLalarmLevel(0L);
                    qstag.setLlValue("0");
                    qstag.setLlAlarmLevel(0L);
                    qstag.setControl(0L);
                    addList.add(qstag);
                }
            });
        }

        //2、再导入点表
        List<DlldrInfo> dllDrInfoList = dlldrInfoService.findAllDllDrInfo(dbName);
        Map<String,Long> dllDrInfoMap = new HashMap<>();
        if(CollectionUtils.isEmpty(dllDrInfoList)){
            return AjaxResult.error(50009, "保存失败，先配置采集设备");
        }
        dllDrInfoList.forEach(dllDrInfo -> {
            String ipAndPort = dllDrInfo.getIpport();
            dllDrInfoMap.put(ipAndPort,dllDrInfo.getDrid());
        });

        /*
         * valueType值类型，格式有：1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
         *
         * Bool 布尔型
         * DINT 32位有符号整形
         * Int 16位有符号整形
         * WORD 2字节16位无符号整形
         * DWORD 32位无符号整形
         * Real 32位浮点数
         * LReal 64位浮点数
         */
        boolean isContinue = true;
        int count = 1;//计数
        String message = "";
        Map<String,String> repeatMap = new HashMap<>();
        for(QstagModbusTcp qsTagModbusTcp : rawList){
            count++;
            String pointName = qsTagModbusTcp.getPointName();//点位名称，中英文格式，如CHP2频率反馈，不适合做用于查询的数据库字段
            String itemId = qsTagModbusTcp.getItemid();//寄存器地址,如40001
            String opt = qsTagModbusTcp.getOpt();
            if(!StringUtils.hasLength(pointName) || !StringUtils.hasLength(itemId)){
                continue;
            }

            //制造数据
            Qstag qstag = new Qstag();
            long valueType = 1L;//1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
            if(StringUtils.hasLength(qsTagModbusTcp.getDataType())){
                valueType = getValueType(qsTagModbusTcp.getDataType().trim().toUpperCase());
            }
            qstag.setValuetype(valueType);//值类型，从dataType转换而来,1、离散型(Bool)，2、长整型(DINT)，3、模拟型(Int)，4、字符型(WORD)，5、浮点型(Real)，6、64位浮点型(LReal)，7、32位无符号整型(DWORD)）
            qstag.setBoolType(valueType == 1 ? 1L : 0L);

            long readType = 1L;
            if(StringUtils.hasLength(qsTagModbusTcp.getReadWrite())){
                readType = getReadWriteType(qsTagModbusTcp.getReadWrite().trim().toUpperCase());
            }
            qstag.setItemreadtype(readType);//读写属性，1只读，2读写，3只写

            String ipAndPort = qsTagModbusTcp.getItemdrid();//格式如：192.168.10.20:502
            if(!StringUtils.hasLength(ipAndPort) || !ipAndPort.contains(":") || ipAndPort.indexOf(":") == 0 || ipAndPort.indexOf(":") == ipAndPort.length() - 1){
                isContinue = false;
                message = "保存失败，先配置通讯点表的第" + count + "行的第“ModbusTCP网关设备地址”列，格式如：192.168.10.20:502，且需要先在“设备采集配置”页面中进行配置。";
                break;
            }
            String port = ipAndPort.split(":")[1];
            String bit = StringUtils.hasLength(qsTagModbusTcp.getBit()) ? ( ":" + qsTagModbusTcp.getBit()) : "";
            String itemIdName = port + "-" + itemId.trim() + bit;
            String tempPointName = pointName.trim();
            if(StringUtils.hasLength(tempPointName) && tempPointName.contains(":")){
                tempPointName = tempPointName.substring(tempPointName.indexOf(":") + 1);
            }
            qstag.setTagname(FormatUtil.getCharAndNumber(tempPointName) + itemIdName);//变量寄存器名称,根据寄存器地址生成
            qstag.setTagnameCN(tempPointName);//变量中文名称
            qstag.setTagvalue("0");//
            qstag.setUnits(StringUtils.hasLength(qsTagModbusTcp.getUnits()) ? qsTagModbusTcp.getUnits() : null);
            qstag.setTagdesc(StringUtils.hasLength(qsTagModbusTcp.getTagdesc()) ? qsTagModbusTcp.getTagdesc() : null);
            qstag.setGroupName(qsTagModbusTcp.getGroupName());
            qstag.setTagvartype(1l);//点位类型，变量数据来源 设备还是公式。或变量类型： 1表示采集变量，值由驱动从设备或者第三方接口产生；2表示内存变量，由采集变量根据计算公式得到。

            qstag.setItemid(itemIdName);//通讯变量寄存器地址

            String drTypeCode = drTypeCodeMap.get(tempPointName);
            qstag.setDrTypeCode(StringUtils.hasLength(drTypeCode) ? drTypeCode : null);

            String name = repeatMap.get(itemIdName);
            if(StringUtils.hasLength(name)){
                //重复地址，禁止
                isContinue = false;
                message = "保存失败，通讯点表的第" + count + "行的“Modbus寄存器地址 + Modbus位:” " + itemIdName + "，这两列地址与之前的地址重复。";
                break;
            }else{
                repeatMap.put(itemIdName,pointName.trim());
            }

            Long itemDrId = dllDrInfoMap.get(ipAndPort);
            if(itemDrId == null || itemDrId <= 0){
                isContinue = false;
                message = "保存失败，先配置通讯点表的第" + count + "行的第“ModbusTCP网关设备地址”列，格式如：192.168.10.20:502，且需要先在“设备采集配置”页面中进行配置。";
                break;
            }
            qstag.setItemdrid(itemDrId);//通讯设备ID，见项目“设备采集管理”“设备采集配置”菜单界面设备采集配置列表的“设备ID”

            qstag.setItemdradd(qsTagModbusTcp.getItemdradd().trim());//设备地址，modbus的从站编号
            String itemXs = qsTagModbusTcp.getItemxs();
            itemXs = !StringUtils.hasLength(itemXs) ? "1" : itemXs.trim();
            qstag.setItemxs(FormatUtil.getNumber(itemXs));//系数
            qstag.setSavetime("5");//默认5分钟存储
            long alarmForbid = 1L;//禁止报警：0否；1是；
            long alarmTag = 0L;//是否报警：0表示不报警；1表示报警
            long alarmLevel = 0L;//报警等级。0不是报警，1一般报警；2.严重报警；3.紧急报警；一般等级就弹窗一次，严重的等级就得播放声音，弹窗，紧急报警要做到微信推送，弹窗，浏览器播放声音。冰机故障算紧急报警，水泵冷却塔报警算严重报警，风柜，传感器的报警算一般报警
            String tempAlarmLevel = qsTagModbusTcp.getAlarmLevel();
            if(StringUtils.hasLength(tempAlarmLevel)){
                try{
                    alarmLevel = Long.parseLong(tempAlarmLevel);
                    if(alarmLevel != 0){
                        alarmForbid = 0;
                        alarmTag = 1;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            qstag.setAlarmforbid(alarmForbid);
            qstag.setAlarmtag(alarmTag);
            qstag.setAlarmlevel(alarmLevel);
            qstag.setAlarmdelay(30L);
            qstag.setHhValue("0");
            qstag.setHhAlarmLevel(0L);
            qstag.setHvalue("0");
            qstag.setHalarmLevel(0L);
            qstag.setLvalue("0");
            qstag.setLalarmLevel(0L);
            qstag.setLlValue("0");
            qstag.setLlAlarmLevel(0L);
            String controlLevel = qsTagModbusTcp.getControlLevel();
            qstag.setControl(StringUtils.hasLength(controlLevel) ? Long.parseLong(controlLevel) : (readType == 1 ? 0L : 1L));
            if(StringUtils.hasLength(opt) && ("取消".equals(opt) || "删除".equals(opt))){
                //删除操作
                deleteList.add(qstag);
            }else{
                addList.add(qstag);//新增或修改
            }
        }

        if(!isContinue){
            log.warn(message);
            return AjaxResult.error(50009, message);
        }

        if(!CollectionUtils.isEmpty(addList)){
            qstagService.importObjectsByImport(dbName, addList, deleteList);
            return AjaxResult.success();
        }
        return AjaxResult.error(50009, "保存失败");
    }

    /**
     * 导入设备
     * @param dbName
     * @param rawList
     * @return
     */
    @Transactional
    @Override
    public AjaxResult importEquipmentList(String dbName, List<DrInfoImport> rawList) {
        //1、配置设备类型
        String dbNameZ = centralDatabase;
        List<Drinfo> drInfoList = new ArrayList<>();//正式设备
        List<Drinfo> virtualDeviceList = new ArrayList<>();//虚拟设备
        Set<String> drTypeCodeSet = new HashSet<>();
        rawList.forEach(drInfoImport -> {
            String drTypeCode = drInfoImport.getDrTypeCode();//设备类型编码
            String drName = drInfoImport.getDrName();//设备名称
            String drCode = drInfoImport.getDrCode();//设备编码
            String isVirtualDevice = drInfoImport.getIsVirtualDevice();
            String attributeName = drInfoImport.getAttributeName();
            String unit = drInfoImport.getUnit();
            if(StringUtils.hasLength(drCode) && drCode.contains(":")){
                drCode = drCode.substring(drCode.indexOf(":") + 1);
            }
            String buildId = drInfoImport.getBuildId();//所属建筑ID
            if(StringUtils.hasLength(drTypeCode) && drInfoImport.getIsHasTemplate() != null && "1".equals(drInfoImport.getIsHasTemplate().trim())){
                drTypeCodeSet.add(drTypeCode);//excel中导入的设备类型
                Drinfo drinfo = new Drinfo();
                drinfo.setDrname(drName);//设备名称
                drinfo.setDrtypeid(0L);//设备类型ID，后面会重新设置，先占位
                if(StringUtils.hasLength(buildId)){
                    long tempBuildId = 0L;
                    try{
                        tempBuildId = Long.parseLong(buildId.trim());
                    }catch (Exception e){
                    }
                    drinfo.setBuildid(tempBuildId == 0 ? null : tempBuildId);
                }
                drinfo.setDrcode(drCode);//设备编码
                drinfo.setDrUseexplain(drName);//用途说明
                drinfo.setDrUsestate(1L);//使用情况
                drinfo.setInfo(drTypeCode.trim());//设备类型编码，先用info存储，下面取出来使用
                drinfo.setDrTypeCode(drTypeCode.trim());//设备类型编码，下面取出来使用
                //建立设备对象，后面创建设备用
                if("0".equals(isVirtualDevice)){
                    drinfo.setTypeYT("1");
                    drInfoList.add(drinfo);
                }else{
                    drinfo.setDrtypename(attributeName);//虚拟设备属性名称，先用Drtypename存储，后面使用完再去掉
                    drinfo.setAreaName(unit);
                    drinfo.setTypeYT("2");
                    virtualDeviceList.add(drinfo);
                }
            }
        });

        Set<Long> drTypeIdSet = new HashSet<>();
        List<Long> drTypeIdList = new ArrayList<>();
        Map<String,Long> drTypeCodeToDrTypeIdMap = new HashMap<>();//存储（drTypeCode，DrTypeId），如（CH，75）
        Map<String,String> qsTagMap = new HashMap<>();
        List<Qstag> qsTagList = qstagService.findAll(dbName);
        qsTagList.forEach(qsTag -> {
            String tagNameCN = qsTag.getTagnameCN();
            if(tagNameCN.contains(":")){
                qsTagMap.put(tagNameCN.substring(tagNameCN.indexOf(":") + 1),tagNameCN);
            }else{
                qsTagMap.put(tagNameCN,tagNameCN);
            }
        });

        if(!CollectionUtils.isEmpty(drTypeCodeSet)){
            List<String> drTypeCodeList = new ArrayList<>();
            drTypeCodeList.addAll(drTypeCodeSet);//excel中导入的设备类型
            Map<Long, Drtypeinfo> map = new HashMap<>();
            List<Drtypeinfo> tempList = drtypeinfoService.findAllDrtypeAndDrReturnList(dbNameZ,0);//返回中心库库中所有的设备类型
            tempList.stream().forEach(drTypeInfo -> {
                map.put(drTypeInfo.getDrtypeid(),drTypeInfo);
                if(drTypeInfo.getDrTypeCode() != null && drTypeCodeList.contains(drTypeInfo.getDrTypeCode().trim())){
                    drTypeIdList.add(drTypeInfo.getDrtypeid());//找到Excel中配置的设备类型ID
                    drTypeCodeToDrTypeIdMap.put(drTypeInfo.getDrTypeCode().trim(),drTypeInfo.getDrtypeid());
                }
            });
            //找所有的父级ID
            if(!CollectionUtils.isEmpty(drTypeIdList)){
                drTypeIdList.stream().forEach(drTypeId ->{
                    drTypeIdSet.add(drTypeId);
                    getParent(drTypeId,map,drTypeIdSet);
                });
            }

            drTypeIdList.clear();
            drTypeIdList.addAll(drTypeIdSet);//
            List<String> tempDrTypeIdList = drTypeIdList.stream().map(String::valueOf).collect(Collectors.toList());

            String drTypeIds = !CollectionUtils.isEmpty(tempDrTypeIdList) ? tempDrTypeIdList.stream().collect(Collectors.joining(",")) : "";//设备类型ID，英文逗号","分隔
            if(!"".equals(drTypeIds)){
                drtypeinfoService.moveDrTypeAndModel(dbName,drTypeIds,qsTagList);
            }
        }

        //2、创建设备/创建虚拟设备
        createDevice(dbName,drInfoList,drTypeCodeToDrTypeIdMap,qsTagMap);//创建真实设备，支持更新
        createVirtualDevice(dbName,virtualDeviceList,drTypeCodeToDrTypeIdMap);//创建虚拟设备，支持更新
        //数据绑定
        dataAndVariableBinding(dbName);
        return AjaxResult.success();
    }

    public void dataAndVariableBinding(String dbName){
        //辅助map，后面方法需要
        Map<Long, Drinfo> drInfoByDrIdMap = new HashMap<>();
        List<Reg> regList = regService.findAllReg(dbName);//变量列表
        List<Drinfo> tempDrInfoList = drinfoService.findAllDrinfo(dbName);//设备列表
        if(!CollectionUtils.isEmpty(tempDrInfoList)){
            tempDrInfoList.stream().forEach(drInfo -> {
                drInfoByDrIdMap.put(drInfo.getDrid(),drInfo);
            });
        }

        /*
         * 该方法处理两个：
         * 3、将设备及其属性变量 与 寄存器地址 进行绑定，以便根据具体设备 能够获取到该设备的所有读取到的属性值
         * 4、检查没有绑定上的变量，根据另外一种规则。根据最长公共串算法，解决tempTagName=CT3通讯状态，tempTagName=CT4通讯状态， tagNameCN=CT3_CT4通讯状态问题（这种情况已经在点表上进行处理，这里不用再处理）
         */
        attributeAndVariableBinding(dbName,regList,drInfoByDrIdMap);

        /*
         * 5、将首页参数（湿球温度、室外湿度、室外温度、露点温度）与寄存器地址绑定，以便在监控WEB端的首页能观察到这些参数的值
         */
        homePageParamSet(dbName);

        /*
         * 6、能耗参数变量绑定，能耗参数做了专门的KEY来查询，见param_type表，因此在将reg表的能耗设备属性与寄存器地址变量绑定时候，虽然已经绑定成功了，
         * 但是能耗设备所绑定的寄存器地址不在param_type表中，在查询能耗图表数据时候无法连表关联查询，因此再次需要根据一些规则重新绑定一下，避免人工操作界面绑定
         */
        energyRegVariableBinding(dbName,drInfoByDrIdMap);

        /*
         * 7、qstag表中itemid = local, itemdrid = 0 的那些虚拟变量 的公式
         */
        energyQsTagVariableBinding(dbName);

        /*
         * 隐藏某些变量
         */
        hideReg(dbName);
    }

    @Override
    public AjaxResult hideReg(String dbName) {
        List<Reg> regList = regService.findAllReg(dbName);
        if(CollectionUtils.isEmpty(regList)){
           return AjaxResult.warn("regList is null");
        }
        List<Drinfo> allDrInfoList = drinfoService.findAllDrinfo(dbName);
        if(CollectionUtils.isEmpty(allDrInfoList)){
            return AjaxResult.warn("allDrInfoList is null");
        }
        Map<Long,Drinfo> drInfoMap = new HashMap<>();
        allDrInfoList.forEach(drInfo -> {
            drInfoMap.put(drInfo.getDrid(),drInfo);
        });
        Map<String,Qstag> qsTagMap = new HashMap<>();
        List<Qstag> qsTagList = qstagService.findAllQsTagOfTagNameCN(dbName);
        if(CollectionUtils.isEmpty(qsTagList)){
            return AjaxResult.warn("qsTagList is null");
        }
        qsTagList.forEach(qsTag -> {
            if(StringUtils.hasLength(qsTag.getTagnameCN())){
                qsTagMap.put(qsTag.getTagnameCN(),qsTag);
            }
        });
        List<Long> hideRegIdList = new ArrayList<>();
        List<Long> showRegIdList = new ArrayList<>();
        regList.forEach(reg -> {
            if(reg != null && reg.getDrId() > 0 && StringUtils.hasLength(reg.getRegName())){
                Long drId = reg.getDrId();
                String regName = reg.getRegName();
                Drinfo drInfo = drInfoMap.get(drId);
                if(drInfo != null && StringUtils.hasLength(drInfo.getDrcode())){
                    String drCode = drInfo.getDrcode();
                    String tagNameCN = drCode + regName;
                    Qstag tempQsTag = qsTagMap.get(tagNameCN);
                    if(tempQsTag != null){
                        //说明该reg对应的设备变量名存在相应的寄存器地址
                        showRegIdList.add(reg.getRegId());
                    }else{
                        //该reg对应的变量名不存在对应的寄存器地址，则该reg不应该显示在界面上，因为没有读到值，界面上显示全部是0
                        //还需要判断其余情况才能确定，如变量绑定的是系统参数里面的值，这个时候就不能隐藏了
                        if(StringUtils.hasLength(reg.getTagName())){
                            //存在变量绑定到其它寄存器地址，说明有值，需要返回显示的
                            showRegIdList.add(reg.getRegId());
                        }else{
                            hideRegIdList.add(reg.getRegId());
                        }
                    }
                }else{
                    //还需要判断其余情况才能确定，如变量绑定的是系统参数里面的值，这个时候就不能隐藏了
                    if(StringUtils.hasLength(reg.getTagName())){
                        //存在变量绑定到其它寄存器地址，说明有值，需要返回显示的
                        showRegIdList.add(reg.getRegId());
                    }else{
                        hideRegIdList.add(reg.getRegId());
                    }
                }
            }
        });
        List<Long> subShowRegIdList = new ArrayList<>();
        if(showRegIdList.size() > 0){
            showRegIdList.forEach(regId -> {
                subShowRegIdList.add(regId);
                if(subShowRegIdList.size() % 50 == 0){
                    try{
                        regService.updateIsThreeDShowByRegIdList(dbName,subShowRegIdList,1);
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        subShowRegIdList.clear();
                    }
                }
            });
            if(subShowRegIdList.size() > 0){
                try{
                    regService.updateIsThreeDShowByRegIdList(dbName,subShowRegIdList,1);
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    subShowRegIdList.clear();
                }
            }
        }

        List<Long> subRegIdList = new ArrayList<>();
        if(hideRegIdList.size() > 0){
            hideRegIdList.forEach(regId -> {
                subRegIdList.add(regId);
                if(subRegIdList.size() % 50 == 0){
                    try{
                        regService.updateIsThreeDShowByRegIdList(dbName,subRegIdList,0);
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        subRegIdList.clear();
                    }
                }
            });
            if(subRegIdList.size() > 0){
                try{
                    regService.updateIsThreeDShowByRegIdList(dbName,subRegIdList,0);
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    subRegIdList.clear();
                }
            }
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult createEquipmentXml(String dbName) {
        List<Drinfo> drInfoList = drinfoService.findAllDrinfo(dbName);
        Map<String,Drinfo> drInfoMap = new HashMap<>();
        drInfoList.forEach(drInfo -> {
            drInfoMap.put(drInfo.getDrcode(),drInfo);
        });

        List<Reg> regList = regService.findAllReg(dbName);
        Map<Long,List<Reg>> regMap = regList.stream().collect(Collectors.groupingBy(Reg::getDrId));
        StringBuilder sb = new StringBuilder();
        createCHP(sb,drInfoMap,regMap);//1、生成冷冻泵的
        createCH(sb,drInfoMap,regMap);//2、生成冷机的
        createCT(sb,drInfoMap,regMap);//3、生成冷却塔的
        createCWP(sb,drInfoMap,regMap);//4、生成冷却泵的
        createHWP(sb,drInfoMap,regMap);//5、生成热水泵的

        return AjaxResult.success("生成成功",sb.toString());

    }

    private void createCHP(StringBuilder sb,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        //<!--	frequencyid 为 频率id（频率反馈 reglist.regId）   -->
        //<Object name="冷冻泵01" modelname="CHP1" drid="1" runningid="2" frequencyid="4"/>
        sb.append("<CHP>").append(System.getProperty("line.separator"));
        for(int i=1;i<=6;i++){
            String nameCode = "0" + i;
            String drCode = "CHP" + i;//如CHP1
            Drinfo drinfo = drInfoMap.get(drCode);
            if(drinfo == null){
                continue;
            }
            Long drid = drinfo.getDrid();
            List<Reg> tempRegList = regMap.get(drid);
            if(tempRegList == null){
                continue;
            }
            String runningid = "";
            String frequencyid = "";
            for(Reg reg : tempRegList){
                String regName = reg.getRegName();
                if("运行".equals(regName)){
                    runningid = String.valueOf(reg.getRegId());
                } else if ("输出频率".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                } else if ("频率反馈".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                }
                if(StringUtils.hasLength(runningid) && StringUtils.hasLength(frequencyid)){
                    break;
                }
            }
            String d = "<Object name=\"冷冻泵" + nameCode + "\" modelname=\"CHP"+ i + "\" drid=\"" + drid + "\" runningid=\"" + runningid + "\" frequencyid=\"" + frequencyid + "\" />";
            sb.append(d).append(System.getProperty("line.separator"));
        }
        sb.append("</CHP>").append(System.getProperty("line.separator"));
    }

    private void createCH(StringBuilder sb,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        String[] chArray = {"CH1","CH2","CH3","CH4"};
        String[] mchArray = {"MCH1","MCH2","MCH3","MCH4"};
        String[] lchArray = {"LCH1","LCH2","LCH3","LCH4"};
        String[] hchArray = {"HCH1","HCH2","HCH3","HCH4"};
        String[] fchArray = {"FCH1","FCH2","FCH3","FCH4"};
        createSubCH(sb,"CH","冷机",chArray,drInfoMap,regMap);
        createSubCH(sb,"MCH","中温冰机",mchArray,drInfoMap,regMap);
        createSubCH(sb,"LCH","低温冰机",lchArray,drInfoMap,regMap);
        createSubCH(sb,"HCH","热回收机组",hchArray,drInfoMap,regMap);
        createSubCH(sb,"FCH","热水机组",fchArray,drInfoMap,regMap);
    }

    private void createSubCH(StringBuilder sb,String chLabel,String drName,String[] chArray,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        //<!-- posltid  冷却回水(进水) poslbid 冷却供水(出水) posrtid 冷冻供水(出水)  posrbid 冷冻回水(进水) load 负荷-->
        //<Object name="冷机04" modelname="CH001" drid="0" runningid="650" runningvalue="1" frequencyid="0" posltid="685" poslbid="686" posrtid="684" posrbid="683" load="682"/>
        sb.append("<" + chLabel + ">").append(System.getProperty("line.separator"));
        for(int i=1;i<=4;i++){
            String nameCode = i < 10 ? "0" + i : "" + i;
            String modelCode = i < 10 ? "00" + i : "0" + i;
            String drCode =  chArray[i-1];//如"CH" + i;//如CH1
            Drinfo drinfo = drInfoMap.get(drCode);
            if(drinfo == null){
                continue;
            }
            Long drid = drinfo.getDrid();
            List<Reg> tempRegList = regMap.get(drid);
            if(tempRegList == null){
                continue;
            }
            String runningid = "";
            String frequencyid = "0";
            String runningvalue = "1";
            String posltid = "";//posltid == 3D左上 冷却回水(进水)
            String poslbid = "";//poslbid == 3D左下 冷却供水(出水)
            String posrtid = "";//posrtid == 3D右上 冷冻供水(出水)
            String posrbid = "";//posrbid == 3D右下 冷冻回水(进水)
            String load = "";
            for(Reg reg : tempRegList){
                String regName = reg.getRegName();
                if("运行".equals(regName)){
                    runningid = String.valueOf(reg.getRegId());
                    //runningvalue = reg.getTagValue();
                } else if ("输出频率".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                }  else if ("频率反馈".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                } else if ("冷却回水温度".equals(regName)) {
                    posltid = String.valueOf(reg.getRegId());
                } else if ("冷却供水温度".equals(regName)) {
                    poslbid = String.valueOf(reg.getRegId());
                } else if ("冷冻供水温度".equals(regName)) {
                    posrtid = String.valueOf(reg.getRegId());
                } else if ("冷冻回水温度".equals(regName)) {
                    posrbid = String.valueOf(reg.getRegId());
                } else if ("运行最大负荷设定".equals(regName)) {
                    load = String.valueOf(reg.getRegId());
                } else if ("最高负荷设定".equals(regName)) {
                    load = String.valueOf(reg.getRegId());
                } else if ("负荷".equals(regName)) {
                    load = String.valueOf(reg.getRegId());
                }
            }
            String d = "<Object name=\"" + drName + "" + nameCode + "\" modelname=\"" + chLabel + ""+ modelCode + "\" drid=\"" + drid + "\" runningid=\"" + runningid + "\" runningvalue=\"" + runningvalue + "\" frequencyid=\"" + frequencyid + "\" posltid=\"" + posltid + "\" poslbid=\"" + poslbid + "\" posrtid=\"" + posrtid + "\" posrbid=\"" + posrbid + "\" load=\"" + load + "\"/>";
            sb.append(d).append(System.getProperty("line.separator"));
        }
        sb.append("</" + chLabel + ">").append(System.getProperty("line.separator"));
    }

    private void createCT(StringBuilder sb,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        String[] ctArray = {"CT11","CT12","CT13","CT14","CT21","CT22","CT23","CT24","CT31","CT32","CT33","CT34","CT41","CT42","CT43","CT44"};
        String[] ctArray2 = {"CT1","CT2","CT3","CT4","CT5","CT6","CT7","CT8","CT9","CT10","CT11","CT12","CT13","CT14","CT15","CT16"};
        //<!--	drid== 数据的drid  runningid == 运行的regId	-->
        //<Object name="冷却塔01" modelname="CT001" drid="16" runningid="614" frequencyid="618"/>
        sb.append("<CT>").append(System.getProperty("line.separator"));
        for(int i=1;i<=16;i++){
            String nameCode = i < 10 ? "0" + i : "" + i;
            String modelCode = i < 10 ? "00" + i : "0" + i;

            String drCode = ctArray[i-1];//如CT11
            Drinfo drinfo = drInfoMap.get(drCode);
            if(drinfo == null){
                drCode = ctArray2[i-1];//如CT1
                drinfo = drInfoMap.get(drCode);
                if(drinfo == null){
                    continue;
                }
            }
            Long drid = drinfo.getDrid();
            List<Reg> tempRegList = regMap.get(drid);
            if(tempRegList == null){
                continue;
            }
            String runningid = "";
            String frequencyid = "";
            for(Reg reg : tempRegList){
                String regName = reg.getRegName();
                if("运行".equals(regName)){
                    runningid = String.valueOf(reg.getRegId());
                } else if ("输出频率".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                } else if ("频率反馈".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                }
                if(StringUtils.hasLength(runningid) && StringUtils.hasLength(frequencyid)){
                    break;
                }
            }
            String d = "<Object name=\"冷却塔" + nameCode + "\" modelname=\"CT"+ modelCode + "\" drid=\"" + drid + "\" runningid=\"" + runningid + "\" frequencyid=\"" + frequencyid + "\" />";
            sb.append(d).append(System.getProperty("line.separator"));
        }
        sb.append("</CT>").append(System.getProperty("line.separator"));
    }

    private void createCWP(StringBuilder sb,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        sb.append("<CWP>").append(System.getProperty("line.separator"));
        for(int i=1;i<=6;i++){
            String nameCode = "0" + i;
            String drCode = "CWP" + i;//如CHP1
            Drinfo drinfo = drInfoMap.get(drCode);
            if(drinfo == null){
                continue;
            }
            Long drid = drinfo.getDrid();
            List<Reg> tempRegList = regMap.get(drid);
            if(tempRegList == null){
                continue;
            }
            String runningid = "";
            String frequencyid = "";
            for(Reg reg : tempRegList){
                String regName = reg.getRegName();
                if("运行".equals(regName)){
                    runningid = String.valueOf(reg.getRegId());
                } else if ("输出频率".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                } else if ("频率反馈".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                }
                if(StringUtils.hasLength(runningid) && StringUtils.hasLength(frequencyid)){
                    break;
                }
            }
            String d = "<Object name=\"冷却泵" + nameCode + "\" modelname=\"CWP"+ i + "\" drid=\"" + drid + "\" runningid=\"" + runningid + "\" frequencyid=\"" + frequencyid + "\" />";
            sb.append(d).append(System.getProperty("line.separator"));
        }
        sb.append("</CWP>").append(System.getProperty("line.separator"));
    }

    private void createHWP(StringBuilder sb,Map<String,Drinfo> drInfoMap,Map<Long,List<Reg>> regMap){
        sb.append("<HWP>").append(System.getProperty("line.separator"));
        for(int i=1;i<=6;i++){
            String nameCode = "0" + i;
            String drCode = "HWP" + i;//如HWP1
            Drinfo drinfo = drInfoMap.get(drCode);
            if(drinfo == null){
                continue;
            }
            Long drid = drinfo.getDrid();
            List<Reg> tempRegList = regMap.get(drid);
            if(tempRegList == null){
                continue;
            }
            String runningid = "";
            String frequencyid = "";
            for(Reg reg : tempRegList){
                String regName = reg.getRegName();
                if("运行".equals(regName)){
                    runningid = String.valueOf(reg.getRegId());
                } else if ("输出频率".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                } else if ("频率反馈".equals(regName)) {
                    frequencyid = String.valueOf(reg.getRegId());
                }
                if(StringUtils.hasLength(runningid) && StringUtils.hasLength(frequencyid)){
                    break;
                }
            }
            String d = "<Object name=\"热水泵" + nameCode + "\" modelname=\"HWP"+ i + "\" drid=\"" + drid + "\" runningid=\"" + runningid + "\" frequencyid=\"" + frequencyid + "\" />";
            sb.append(d).append(System.getProperty("line.separator"));
        }
        sb.append("</HWP>").append(System.getProperty("line.separator"));
    }

    private void createDevice(String dbName,List<Drinfo> drInfoList,Map<String,Long> drTypeCodeToDrTypeIdMap,Map<String,String> qsTagMap){
        drInfoList.stream().forEach(drInfo -> {
            Long drTypeId = drTypeCodeToDrTypeIdMap.get(drInfo.getDrTypeCode());//存储（drTypeCode，DrTypeId），如（CH，75）
            drInfo.setDrtypeid(drTypeId);
            drInfo.setInfo(null);
            drInfo.setDrTypeCode(null);
            drInfo.setDrtypename(null);
            drInfo.setAreaName(null);
            if(drInfo.getDrtypeid() == null || drInfo.getDrname() == null){
                log.debug("drTypeId:{},getDrName:{},drCode:{}",drInfo.getDrtypeid(),drInfo.getDrname(),drInfo.getDrcode());
            }
        });
        //排序设备列表,以drtypeid升序和drname升序
        List<Drinfo> drInfoSortedList = drInfoList.stream().sorted(Comparator.comparing(Drinfo::getDrtypeid).thenComparing(Drinfo::getDrname)).collect(Collectors.toList());
        List<Drinfo> oldList = drinfoService.findAllDrinfo(dbName);
        for (Drinfo drinfo : drInfoSortedList) {
            if(oldList != null && oldList.size() > 0){
                //更新或插入
                drinfoService.saveOrUpdateDevice(dbName, drinfo,qsTagMap,oldList);
            }else{
                //插入
                drinfoService.saveDevice(dbName, drinfo,qsTagMap);
            }
        }
    }

    private void createVirtualDevice(String dbName,List<Drinfo> virtualDeviceList,Map<String,Long> drTypeCodeToDrTypeIdMap){
        virtualDeviceList.stream().forEach(drInfo -> {
            Long drTypeId = drTypeCodeToDrTypeIdMap.get(drInfo.getDrTypeCode());
            drInfo.setDrtypeid(drTypeId);
            drInfo.setInfo(null);
            drInfo.setDrTypeCode(null);
        });
        //排序设备列表,以drtypeid升序和drname升序
        List<Drinfo> drInfoSortedList = virtualDeviceList.stream().sorted(Comparator.comparing(Drinfo::getDrtypeid).thenComparing(Drinfo::getDrname)).collect(Collectors.toList());
        List<Drinfo> oldList = drinfoService.findAllDrinfo(dbName);
        List<RegGroup> groupList = regGroupMapper.findAllRegGroup(dbName);
        for (Drinfo drInfo : drInfoSortedList) {
            drinfoService.saveVirtualDevice(dbName, drInfo, oldList,groupList);
        }
    }

    private void attributeAndVariableBinding(String dbName,List<Reg> regList,Map<Long, Drinfo> drInfoByDrIdMap){
        //3、将设备及其模板变量 与 寄存器地址 进行绑定，以便根据具体设备 能够获取到该设备的所有读取到的属性值
        if(!CollectionUtils.isEmpty(regList) && !drInfoByDrIdMap.isEmpty()){
            for(Reg reg : regList){
                Long drId = reg.getDrId();
                String regName = reg.getRegName();//设备变量名
                Drinfo drinfo = drInfoByDrIdMap.get(drId);
                if(drinfo == null){
                    continue;//继续下一个设备属性
                }
                String drCode = drinfo.getDrcode();//设备编码
                String drName = drinfo.getDrname();//设备名称
                boolean isFind = false;
                if(StringUtils.hasLength(drCode)){
                    String firstChar = regName.substring(0,1);
                    boolean isChinese = FormatUtil.isContainChinese(firstChar);
                    String tempTagName = drCode + (isChinese ? "" : "-") + regName;//格式如CH
                    List<Qstag> qsTagList = qstagService.findAllByTagNameLike(dbName,drCode);//导入点位表数据时候，TagName由drCode生成，因此能够模糊查询到数据
                    if(!CollectionUtils.isEmpty(qsTagList)){
                        for(Qstag qsTag : qsTagList){
                            String tagNameCN = qsTag.getTagnameCN();
                            if(tempTagName.equals(tagNameCN)){
                                //匹配到
                                String tagName = qsTag.getTagname();//寄存器地址变量
                                Reg tempReg = new Reg();
                                tempReg.setRegId(reg.getRegId());
                                tempReg.setTagName(tagName);
                                tempReg.setTagValue(qsTag.getTagvalue());
                                regService.updateTagNameByRegId(dbName,tempReg);//将模板变量 绑定 寄存器地址变量
                                isFind = true;
                                break;
                            }
                        }
                    }
                }
                if(!isFind){
                    //如果没有匹配到，尝试直接根据名称查询看是否匹配
                    Qstag tempQsTag = qstagService.findObjectByTagNameCnEquals(dbName,regName);
                    if(tempQsTag != null){
                        String tagName = tempQsTag.getTagname();//寄存器地址变量
                        Reg tempReg = new Reg();
                        tempReg.setRegId(reg.getRegId());
                        tempReg.setTagName(tagName);
                        tempReg.setTagValue(tempQsTag.getTagvalue());
                        regService.updateTagNameByRegId(dbName,tempReg);//将模板变量 绑定 寄存器地址变量
                    }
                }
            }
        }

        //4、检查没有绑定上的变量，根据另外一种规则。根据最长公共串算法，解决tempTagName=CT3通讯状态，tempTagName=CT4通讯状态， tagNameCN=CT3_CT4通讯状态问题(已经从点表上进行处理，暂时不用了)
        /*List<Reg> nullRegList = regService.findAllRegByNullTagName(dbName);//变量列表
        if(!CollectionUtils.isEmpty(nullRegList)){
            nullRegList.forEach(reg -> {
                Integer drId = reg.getDrId();
                String regName = reg.getRegName();//设备变量名
                Drinfo drinfo = groupByDrIdMap.get(drId);
                if(drinfo != null){
                    String drCode = drinfo.getDrcode();//设备编码
                    String drName = drinfo.getDrname();//设备名称
                    if(StringUtils.hasLength(drCode)){
                        String tempTagName = drCode + regName;
                        List<Qstag> qsTagList = qstagService.findAllByTagNameLike(dbName,drCode);//导入点位表数据时候，TagName由drCode生成，因此能够模糊查询到数据
                        if(!CollectionUtils.isEmpty(qsTagList)){
                            qsTagList.forEach(qsTag -> {
                                String tagNameCN = qsTag.getTagnameCN();
                                if(StringUtils.hasLength(tempTagName) && StringUtils.hasLength(tagNameCN) && tempTagName.length() < tagNameCN.length()){
                                    //最长公共串算法，解决tempTagName=CT3通讯状态，tempTagName=CT4通讯状态， tagNameCN=CT3_CT4通讯状态，问题
                                    if(tagNameCN.contains(drCode) && tagNameCN.contains(regName)){
                                        int len = getLongestCommonSubstring(tempTagName,tagNameCN);
                                        if(len == tempTagName.length() || len == regName.length() || len == drCode.length()){
                                            //找到
                                            String tagName = qsTag.getTagname();//寄存器地址变量
                                            Reg tempReg = new Reg();
                                            tempReg.setRegId(reg.getRegId());
                                            tempReg.setTagName(tagName);
                                            tempReg.setTagValue(qsTag.getTagvalue());
                                            regService.updateTagNameByRegId(dbName,tempReg);//将模板变量 绑定 寄存器地址变量
                                        }
                                    }
                                }
                            });
                        }
                    }
                }
            });
        }*/
    }

    /**
     * 首页显示的参数设置。如：湿球温度、室外湿度、室外温度、实时总功率、实时总电量、实时总冷量、冷站效率、热不平衡率、冷水机组COP、冷冻水泵COP、冷却塔COP、冷却水泵COP、
     * 冷冻水温差、冷却水温差、冷冻出水温度、冷却回水温度
     */
    private void homePageParamSet(String dbName){
        List<HomepageParam> homePageParamList = homePageService.findHomepageParam(dbName);
        if(!CollectionUtils.isEmpty(homePageParamList)){
            Long rhtTagId = 0L;//室外温度id
            Long rhhTagId = 0L;//室外湿度id
            String[] paramArray = {"湿球温度","室外湿度","室外温度"};//先设定更新这几个，后面根据业务再看是否更新全部
            List<String> paramList = Arrays.asList(paramArray);
            for(HomepageParam homepageParam : homePageParamList){
                String paramName = homepageParam.getParamName();
                if(!StringUtils.hasLength(paramName)){
                    return;
                }
                if (paramList.contains(paramName.trim())){
                    Qstag qstag = qstagService.findObjectByTagNameCnEquals(dbName,paramName);
                    if(qstag == null){
                        //室外湿度 = RHH当前值,室外温度 = RHT当前值
                        if("室外湿度".equals(paramName)){
                            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"RHH当前值");
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"RHH室外湿度");
                            }
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY室外湿度");
                            }
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"室外湿度");
                            }
                        }else if("室外温度".equals(paramName)){
                            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"RHT当前值");
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"RHT室外温度");
                            }
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY室外温度");
                            }
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"室外温度");
                            }
                        }else if("湿球温度".equals(paramName)){
                            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"湿球温度");
                            if(qstag == null){
                                qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY湿球温度");
                            }
                        }
                    }
                    if(qstag != null){
                        if("室外湿度".equals(paramName)){
                            rhhTagId = qstag.getTagid();
                        }else if("室外温度".equals(paramName)){
                            rhtTagId = qstag.getTagid();
                        }
                        String tagName = qstag.getTagname();
                        HomepageParam tempParam = new HomepageParam();
                        tempParam.setId(homepageParam.getId());
                        tempParam.setTagname(tagName);
                        tempParam.setParamName(paramName);
                        homePageService.updateHomePageParamTagNameById(dbName,tempParam);
                    }
                }
            }

            //单独设置露点温度（TDTemperature）计算公式处理。
            //露点温度计算公式的具体内容是: Td = 243.12 * ((Math.LOG10E * Math.log(RH) - 2) / 0.4343 + (17.62 * T) / (243.12 + T)) / (17.62 - ((Math.LOG10E * Math.log(RH) - 2) / 0.4343 + (17.62 * T) / (243.12 + T)))，
            // 其中Td表示露点温度，T表示室外温度，RH表示相对湿度，Math.LOG10E * Math.log(RH)为求以10为底值为RH的对数。
            //热不平衡率 =（（实时总冷量  + 主机总功率（CH1功率 ... CH4功率 相加） - 瞬时散热量 ）/ 瞬时散热量）* 100
            String T = "@" + rhtTagId + "@";
            String RH = "@" + rhhTagId + "@";
            String TDTemperature = "243.12 * ((Math.LOG10E * Math.log(" + RH + ") - 2) / 0.4343 + (17.62 * " + T + ") / (243.12 + " + T + ")) / (17.62 - ((Math.LOG10E * Math.log(" + RH + ") - 2) / 0.4343 + (17.62 * " + T + ") / (243.12 + " + T + ")))";
            if(rhtTagId > 0 && rhhTagId > 0){
                Qstag qstag = new Qstag();
                qstag.setTagname("TDTemperature");//露点温度
                qstag.setTagformula(TDTemperature);
                int rows = qstagService.updateFormulaByTagName(dbName, qstag);
                if (rows == 1) {
                    //更新成功,do nothing
                }
            }

            //其它参数，如实时总功率、实时总电量、实时总冷量、冷站效率、热不平衡率、冷水机组COP、冷冻水泵COP、冷却塔COP、冷却水泵COP。
            //其中，后面四个可能匹配不到：冷冻水温差、冷却水温差、冷冻出水温度、冷却回水温度，就需要手动写公式
            homePageOtherParamSet(dbName);
        }
    }

    /**
     * 首页其它参数设置。
     * 其它参数，如实时总功率、实时总电量、实时总冷量、冷站效率、热不平衡率、冷水机组COP、冷冻水泵COP、冷却塔COP、冷却水泵COP。
     * 其中，冷冻水温差、冷却水温差、冷冻出水温度、冷却回水温度，这四个可能匹配不到，就需要手动写公式。
     * @param dbName
     */
    private void homePageOtherParamSet(String dbName){
        Qstag qstag = new Qstag();
        //主机总功率 = CH1功率 ... CH4功率 相加
        String totalChPower = getTotalChPowerFormula(dbName,"CH","CH%功率");
        qstag.setTagname("totalChPower");//主机总功率
        qstag.setTagformula(totalChPower);
        int rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        //冷冻泵总功率 = CHP1 CHPS1  ... CHP4 的功率相加
        String totalChpPower = getTotalChPowerFormula(dbName,"CHP","CH%功率");
        qstag.setTagname("totalChpPower");//冷冻泵总功率
        qstag.setTagformula(totalChpPower);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        //冷却塔总功率 = CT11 CT12  ... CT41 的功率相加
        String totalCtPower = getTotalChPowerFormula(dbName,"CT","CT%功率");
        qstag.setTagname("totalCtPower");//冷却塔总功率
        qstag.setTagformula(totalCtPower);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        //冷却泵总功率 = CWP1 CWPS1  ... CWP4 的功率相加
        String totalCwpPower = getTotalChPowerFormula(dbName,"CWP","CWP%功率");
        qstag.setTagname("totalCwpPower");//冷却泵总功率
        qstag.setTagformula(totalCwpPower);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        //实时总功率 = 所有主机CH1...N的功率、冷冻水泵CHP1...N的功率、冷却水泵CWP1...N的功率、冷却塔风机CTF1...N的功率、冷却塔CT1...N的功率相加
        String totalPower = totalChPower + "+" + totalChpPower + "+" + totalCtPower + "+" + totalCwpPower;
        Long totalPowerTagId = 0L;//实时总功率TagId
        qstag.setTagname("totalPower");//实时总功率
        qstag.setTagformula(totalPower);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalPower");//查询实时总功率的tagid,后面用到
            totalPowerTagId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //实时总电量 = 所有主机CH1...N的电量、冷冻水泵CHP1...N的电量、冷却水泵CWP1...N的电量、冷却塔风机CTF1...N的电量、冷却塔CT1...N的电量相加
        String totalElectricity = getTotalChPowerFormula(dbName,"电量","电量");
        Long totalElectricityTagId = 0L;//实时总电量TagId
        qstag.setTagname("totalElectricity");//实时总电量
        qstag.setTagformula(totalElectricity);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalElectricity");//查询实时总电量的tagid,后面用到
            totalElectricityTagId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //实时总冷量 = 实时总冷量（瞬时制冷量（kw）） = 所有这些 北门冷冻制冷功率 + 南门冷冻制冷功率 + 北二门冷冻制冷功率 相加
        String totalCoolingCapacity = getTotalChPowerFormula(dbName,"制冷功率","制冷%功率");
        Long totalCoolingCapacityTagId = 0L;
        qstag.setTagname("totalCoolingCapacity");//实时总冷量
        qstag.setTagformula(totalCoolingCapacity);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalCoolingCapacity");//查询实时总冷量的tagid,后面用到
            totalCoolingCapacityTagId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷站效率 = 冷站效率（系统能效，或叫 冷站效率COP） = 实时总冷量 / 实时总功率，无单位
        String coldStationCop = "(" + "@" + totalCoolingCapacityTagId + "@" + ")" + "/" + "(" + "@" + totalPowerTagId + "@" + ")";
        if(totalCoolingCapacityTagId > 0 && totalPowerTagId > 0){
            qstag.setTagname("coldStationCop");//冷站效率COP
            qstag.setTagformula(coldStationCop);
            rows = qstagService.updateFormulaByTagName(dbName, qstag);
            if (rows == 1) {
                //更新成功,do nothing
            }
        }

        //瞬时散热量，（冷却主管瞬时散热量(instantaneousHeatDissipation)？制热功率）（下面相加）。LQE1大冰机-冷却制热功率  + LQE2小冰机-冷却制热功率
        String InstantaneousHeat = getTotalChPowerFormula(dbName,"制热功率","制热%功率");
        Long InstantaneousHeatId = 0L;
        qstag.setTagname("instantaneousHeatDissipation");//冷却主管瞬时散热量
        qstag.setTagformula(InstantaneousHeat);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"instantaneousHeatDissipation");//查询冷却主管瞬时散热量的tagid,后面用到
            InstantaneousHeatId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷冻主管累计制冷量refrigeratingCapacityOfCoolingStation
        String refrigeratingCapacityOfCoolingStation = getTotalChPowerFormula(dbName,"制冷量","制冷量");
        qstag.setTagname("refrigeratingCapacityOfCoolingStation");//冷冻主管累计制冷量
        qstag.setTagformula(refrigeratingCapacityOfCoolingStation);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功,do nothing
        }

        //冷却主管累计散热量cumulativeHeatDissipation
        String cumulativeHeatDissipation = getTotalChPowerFormula(dbName,"散热量","散热量");
        qstag.setTagname("cumulativeHeatDissipation");//冷却主管累计散热量
        qstag.setTagformula(cumulativeHeatDissipation);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功,LZZLZ
            qstag.setTagname("LZZLZ");//冷站总散热量
            qstag.setTagformula(cumulativeHeatDissipation);
            qstagService.updateFormulaByTagName(dbName, qstag);
        }

        //热不平衡率 =（（实时总冷量  + 主机总功率（CH1功率 ... CH4功率 相加） - 瞬时散热量 ）/ 瞬时散热量）* 100
        String thermalUnbalanceRate = "(" + "(" + "@" + totalCoolingCapacityTagId + "@" + "+" + totalChPower + "-" + "(" + "@" + InstantaneousHeatId + "@" + ")" + ")" + "/" + "(" + "@" + InstantaneousHeatId + "@" + ")" + ")" + "*100";
        if(InstantaneousHeatId > 0){
            qstag.setTagname("thermalUnbalanceRate");//热不平衡率
            qstag.setTagformula(thermalUnbalanceRate);
            rows = qstagService.updateFormulaByTagName(dbName, qstag);
            if (rows == 1) {
                //更新成功,do nothing
            }
        }

        //冷水机组COP（主机能效）= 实时总冷量 / 主机总功率（CH1功率 ... CH4功率 相加）
        String chillerCop = "(" + "@" + totalCoolingCapacityTagId + "@" + ")" + "/" + "(" + totalChPower + ")";
        Long chillerCopId = 0L;
        qstag.setTagname("chillerCop");//冷水机组COP
        qstag.setTagformula(chillerCop);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"chillerCop");//查询冷水机组COP的tagid,后面用到
            chillerCopId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷冻水泵COP（冷冻泵输送系数） = 实时总冷量 / 冷冻泵总功率（CHP1 CHPS1  ... CHP4 的功率相加）
        String chilledWaterPumpCop = "(" + "@" + totalCoolingCapacityTagId + "@" + ")" + "/" + "(" + totalChpPower + ")";
        Long chilledWaterPumpCopId = 0L;
        qstag.setTagname("chilledWaterPumpCop");//冷冻水泵COP
        qstag.setTagformula(chilledWaterPumpCop);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"chilledWaterPumpCop");//查询冷冻水泵COP的tagid,后面用到
            chilledWaterPumpCopId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷却塔COP（冷却塔输送系数） = 实时总冷量 / 冷却塔风机总功率（CT11 CT12  ... CT41 的功率相加）
        String coolingTowerCop = "(" + "@" + totalCoolingCapacityTagId + "@" + ")" + "/" + "(" + totalCtPower + ")";
        Long coolingTowerCopId = 0L;
        qstag.setTagname("coolingTowerCop");//冷却塔COP
        qstag.setTagformula(coolingTowerCop);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"coolingTowerCop");//查询冷却塔COP的tagid,后面用到
            coolingTowerCopId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷却水泵COP（冷却泵输送系数） = 实时总冷量 / 冷却泵总功率（CWP1 CWPS1  ... CWP4 的功率相加）
        String coolingWaterPumpCop = "(" + "@" + totalCoolingCapacityTagId + "@" + ")" + "/" + "(" + totalCwpPower + ")";
        Long coolingWaterPumpCopId = 0L;
        qstag.setTagname("coolingWaterPumpCop");//冷却水泵COP
        qstag.setTagformula(coolingWaterPumpCop);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"coolingWaterPumpCop");//查询冷却水泵COP的tagid,后面用到
            coolingWaterPumpCopId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //冷站总COP = 冷水机组COP + 冷冻水泵COP + 冷却塔COP + 冷却水泵COP
        String totalCopOfCoolingStation = "@" + chillerCopId + "@" + "+" + "@" + chilledWaterPumpCopId + "@" + "+" + "@" + coolingTowerCopId + "@" + "+" + "@" + coolingWaterPumpCopId + "@";
        qstag.setTagname("totalCopOfCoolingStation");//冷站总COP
        qstag.setTagformula(totalCopOfCoolingStation);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }
        qstag = null;

        //冷冻出水温度(冷冻供水总管温度)coolingRturnWaterTemperature
        Long freezingOutWaterTemperatureId = 0L;
        qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷冻总管供水温度");
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷冻主管供水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷冻主管供水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷冻总管供水温度");
            if(qstag == null){
                List<Qstag> qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷冻总管供水温度");
                if(qsTagList == null || qsTagList.size() == 0){
                    qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷冻主管供水温度");
                }
                if(qsTagList != null && qsTagList.size() > 0){
                    qstag = qsTagList.get(0);
                }
            }
        }

        if(qstag != null){
            String freezingOutWaterTemperature = "@" + qstag.getTagid() + "@";
            freezingOutWaterTemperatureId = qstag.getTagid();
            Qstag tempQsTag = new Qstag();
            tempQsTag.setTagname("coolingRturnWaterTemperature");//冷冻出水温度
            tempQsTag.setTagformula(freezingOutWaterTemperature);
            rows = qstagService.updateFormulaByTagName(dbName, tempQsTag);
        }

        qstag = null;

        //冷冻回水温度(冷冻回水总管温度)LDHSWD
        Long freezingInWaterTemperatureId = 0L;
        qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷冻总管回水温度");
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷冻主管回水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷冻主管回水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷冻总管回水温度");
            if(qstag == null){
                List<Qstag> qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷冻总管回水温度");
                if(qsTagList == null || qsTagList.size() == 0){
                    qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷冻主管回水温度");
                }
                if(qsTagList != null && qsTagList.size() > 0){
                    qstag = qsTagList.get(0);
                }
            }
        }
        if(qstag != null){
            String freezingInWaterTemperature = "@" + qstag.getTagid() + "@";
            freezingInWaterTemperatureId = qstag.getTagid();
            Qstag tempQsTag = new Qstag();
            tempQsTag.setTagname("LDHSWD");//冷冻回水温度
            tempQsTag.setTagformula(freezingInWaterTemperature);
            rows = qstagService.updateFormulaByTagName(dbName, tempQsTag);
        }

        qstag = null;

        //冷却回水温度(冷却回水总管温度)coolingWaterTemperature
        Long coolingInWaterTemperatureId = 0L;
        qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷却总管回水温度");
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷却主管回水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷却主管回水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷却总管回水温度");
            if(qstag == null){
                List<Qstag> qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷却总管回水温度");
                if(qsTagList == null || qsTagList.size() == 0){
                    qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷却主管回水温度");
                }
                if(qsTagList != null && qsTagList.size() > 0){
                    qstag = qsTagList.get(0);
                }
            }
        }
        if(qstag != null){
            String coolingInWaterTemperature = "@" + qstag.getTagid() + "@";
            coolingInWaterTemperatureId = qstag.getTagid();
            Qstag tempQsTag = new Qstag();
            tempQsTag.setTagname("coolingWaterTemperature");//冷冻出水温度
            tempQsTag.setTagformula(coolingInWaterTemperature);
            rows = qstagService.updateFormulaByTagName(dbName, tempQsTag);
        }

        //冷却出水温度(冷却供水总管温度)LQCSWD
        Long coolingOutWaterTemperatureId = 0L;
        qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷却总管供水温度");
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"冷却主管供水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷却主管供水温度");
        }
        if(qstag == null){
            qstag = qstagService.findObjectByTagNameCnEquals(dbName,"SY冷却总管供水温度");
            if(qstag == null){
                List<Qstag> qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷却总管供水温度");
                if(qsTagList == null || qsTagList.size() == 0){
                    qsTagList = qstagService.findAllByTagNameCNLike(dbName,"冷却主管供水温度");
                }
                if(qsTagList != null && qsTagList.size() > 0){
                    qstag = qsTagList.get(0);
                }
            }
        }
        if(qstag != null){
            String coolingOutWaterTemperature = "@" + qstag.getTagid() + "@";
            coolingOutWaterTemperatureId = qstag.getTagid();
            Qstag tempQsTag = new Qstag();
            tempQsTag.setTagname("LQCSWD");//冷却出水温度
            tempQsTag.setTagformula(coolingOutWaterTemperature);
            rows = qstagService.updateFormulaByTagName(dbName, tempQsTag);
        }


        qstag = new Qstag();
        //冷冻水温差 = 冷冻回水总管温度 - 冷冻供水总管温度，（回水 - 供水）或（进水 - 出水）
        String chilledWaterTemperatureDifference = "@" + freezingInWaterTemperatureId + "@" + "-" + "@" + freezingOutWaterTemperatureId + "@";
        qstag.setTagname("chilledWaterTemperatureDifference");//冷站总COP
        qstag.setTagformula(chilledWaterTemperatureDifference);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        //冷却水温差 = 冷却供水总管温度 - 冷却回水总管温度，（供水 - 回水）或（出水 - 进水）
        String chilledOutWaterTemperatureDifference = "@" + coolingOutWaterTemperatureId + "@" + "-" + "@" + coolingInWaterTemperatureId + "@";
        qstag.setTagname("chilledOutWaterTemperatureDifference");//冷站总COP
        qstag.setTagformula(chilledOutWaterTemperatureDifference);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }
    }

    /**
     * 能耗参数变量绑定，能耗参数做了专门的KEY来查询，见param_type表，因此,在将reg表的能耗设备属性与寄存器地址变量绑定后，虽然已经绑定成功了，
     * 但是能耗设备所绑定的寄存器地址不在param_type表中，在查询能耗图表数据时候无法连表关联查询，因此再次需要根据一些规则重新绑定一下，避免人工操作界面绑定
     * @param dbName
     * @param drInfoByDrIdMap
     */
    private void energyRegVariableBinding(String dbName,Map<Long, Drinfo> drInfoByDrIdMap){
        List<Reg> energyRegList = regService.findAllByIsEnergy(dbName,"1");//能耗变量的列表，去对应的项目库（dbName）的表（reg）中查询所有能量记录行
        if(energyRegList == null || energyRegList.size() == 0){
            return;
        }
        for(Reg reg : energyRegList){
            try{
                String regName = reg.getRegName();
                if(StringUtils.hasLength(regName) && regName.contains("电量")){
                    Long drId = reg.getDrId();
                    Drinfo drinfo = drInfoByDrIdMap.get(drId);
                    if(drinfo != null){
                        String drName = drinfo.getDrname();//值如：CHP总电量、CHP1电量
                        String drCode = drinfo.getDrcode();//值如：CHPE、CHP1
                        if(drName != null && drName.contains("总电量")){
                            handlerTotal(dbName,drCode,reg);
                            continue;
                        }
                        String key = FormatUtil.getCharAndNumber(drName);
                        if(StringUtils.hasLength(key) && key.contains("-")){
                            key = key.substring(0,key.indexOf("-"));
                        }
                        String newRegName = null;
                        if(key.contains("1")){
                            newRegName = "1号";
                        }else if(key.contains("2")){
                            newRegName = "2号";
                        }else if(key.contains("3")){
                            newRegName = "3号";
                        }else if(key.contains("4")){
                            newRegName = "4号";
                        }else if(key.contains("5")){
                            newRegName = "5号";
                        }else if(key.contains("6")){
                            newRegName = "6号";
                        }else if(key.contains("7")){
                            newRegName = "7号";
                        }else if(key.contains("8")){
                            newRegName = "8号";
                        }else if(key.contains("9")){
                            newRegName = "9号";
                        }else if(key.contains("10")){
                            newRegName = "10号";
                        }
                        //CHPE、CHE、CTE、CWPE、HWPE、QXE
                        if(drCode != null){
                            if(drCode.contains("CHP")){//冷冻泵
                                newRegName = newRegName + "冷冻泵电能";
                            }else if(drCode.contains("MCH")){//中温冰机
                                newRegName = newRegName + "中温冰机电能";
                            }else if(drCode.contains("LCH")){//低温冰机
                                newRegName = newRegName + "低温冰机电能";
                            }else if(drCode.contains("HCH")){//热回收机组
                                newRegName = newRegName + "热回收机组电能";
                            }else if(drCode.contains("FCH")){//热水机组
                                newRegName = newRegName + "热水机组电能";
                            }else if(drCode.contains("CH")){//冷机
                                newRegName = newRegName + "冷机电能";
                            }else if(drCode.contains("CWP")){//冷却泵
                                newRegName = newRegName + "冷却泵电能";
                            }else if(drCode.contains("CT")){//冷却塔
                                log.debug(drCode);
                                if(StringUtils.hasLength(newRegName)){
                                    newRegName = newRegName.substring(0,newRegName.length()-1) + "组冷却塔电能";
                                }else{
                                    newRegName = "1组冷却塔电能";
                                }
                            }else if(drCode.contains("HWP")){//热水泵
                                newRegName = newRegName + "热水泵电能";
                            }else if(drCode.contains("QX")){//水处理
                                newRegName = newRegName + "水处理电能";
                            }
                        }
                        if(newRegName != null){
                            List<ParamType> list = paramTypeService.findParamTypeByRegName(newRegName);//去数据库(中心库)表(param_type)中查询中心库.param_type
                            if(list != null && list.size() > 0){
                                ParamType paramType = list.get(0);
                                String tagName = paramType.getTagName();
                                Reg tempReg = new Reg();
                                tempReg.setRegId(reg.getRegId());
                                tempReg.setTagName(tagName);
                                regService.updateTagNameByRegId(dbName,tempReg);//将模板变量 绑定 寄存器地址变量
                            }
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("energyRegVariableBinding Exception",e);
            }
        }
    }

    private void handlerTotal(String dbName,String drCode,Reg reg){
        try{
            String newRegName = null;
            //CHPE、CHE、CTE、CWPE、HWPE、QXE、LZE
            if(drCode != null){
                if(drCode.contains("CHP")){//冷冻泵
                    newRegName = "冷冻泵总电能";
                }else if(drCode.contains("MCH")){//中温冰机
                    newRegName = "中温冰机总电能";
                }else if(drCode.contains("LCH")){//低温冰机
                    newRegName = "低温冰机总电能";
                }else if(drCode.contains("HCH")){//热回收机组
                    newRegName = "热回收机组总电能";
                }else if(drCode.contains("FCH")){//热水机组
                    newRegName = "热水机组总电能";
                }else if(drCode.contains("CH")){//冷机
                    newRegName = "冷机总电能";
                }else if(drCode.contains("CWP")){//冷却泵
                    newRegName = "冷却泵总电能";
                }else if(drCode.contains("CT")){//冷却塔
                    newRegName = "冷却塔总电能";
                }else if(drCode.contains("HWP")){//热水泵
                    newRegName = "热水泵总电能";
                }else if(drCode.contains("QX")){//水处理
                    newRegName = "水处理总电能";
                }else if(drCode.contains("LZ")){//冷站总电量
                    newRegName = "冷站总电能";
                }
            }
            if(newRegName != null){
                Qstag qsTag = qstagService.findObjectByTagNameCnEquals(dbName,newRegName);//去数据库(中心库)表(param_type)中查询中心库.param_type
                if(qsTag != null){
                    String tagName = qsTag.getTagname();
                    Reg tempReg = new Reg();
                    tempReg.setRegId(reg.getRegId());
                    tempReg.setTagName(tagName);
                    regService.updateTagNameByRegId(dbName,tempReg);//将模板变量 绑定 寄存器地址变量
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * qstag表中itemid = local, itemdrid = 0 的那些虚拟变量 与本表的寄存器地址记录进行绑定
     * @param dbName
     */
    private void energyQsTagVariableBinding(String dbName){
        //totalEnergyConsumptionOfRefrigerationPump 冷冻泵总能耗
        String totalEnergyConsumptionOfRefrigerationPump = getTotalChPowerFormula(dbName,"CHP","CHP%电量");
        Long totalEnergyCHPId = 0L;
        Qstag qstag = new Qstag();
        qstag.setTagname("totalEnergyConsumptionOfRefrigerationPump");//冷冻泵总能耗
        qstag.setTagformula(totalEnergyConsumptionOfRefrigerationPump);
        int rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalEnergyConsumptionOfRefrigerationPump");//查询冷冻泵总能耗的tagid,后面用到
            totalEnergyCHPId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //totalEnergyConsumptionOfCoolingPump 冷却泵总能耗
        String totalEnergyConsumptionOfCoolingPump = getTotalChPowerFormula(dbName,"CWP","CWP%电量");
        Long totalEnergyCWPId = 0L;
        qstag.setTagname("totalEnergyConsumptionOfCoolingPump");//冷却泵总能耗
        qstag.setTagformula(totalEnergyConsumptionOfCoolingPump);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalEnergyConsumptionOfCoolingPump");//查询冷却泵总能耗的tagid,后面用到
            totalEnergyCWPId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //totalEnergyConsumptionOfChiller 冷水机组总能耗
        String totalEnergyConsumptionOfChiller = getTotalChPowerFormula(dbName,"CH","CH%电量");
        Long totalEnergyCHId = 0L;
        qstag.setTagname("totalEnergyConsumptionOfChiller");//冷水机组总能耗
        qstag.setTagformula(totalEnergyConsumptionOfChiller);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalEnergyConsumptionOfChiller");//查询冷却泵总能耗的tagid,后面用到
            totalEnergyCHId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //totalEnergyConsumptionOfCoolingTower 冷却塔总能耗
        String totalEnergyConsumptionOfCoolingTower = getTotalChPowerFormula(dbName,"CT","CT%电量");
        Long totalEnergyCTId = 0L;
        qstag.setTagname("totalEnergyConsumptionOfCoolingTower");//冷却塔总能耗
        qstag.setTagformula(totalEnergyConsumptionOfCoolingTower);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
            Qstag tempQsTag = qstagService.findObjectByTagNameEquals(dbName,"totalEnergyConsumptionOfCoolingTower");//查询冷却泵总能耗的tagid,后面用到
            totalEnergyCTId = tempQsTag != null ? tempQsTag.getTagid() : 0;
        }

        //electricEnergyOfCoolingStation 冷站总电能 =  冷冻泵总能耗 + 冷却泵总能耗 + 冷水机组总能耗 + 冷却塔总能耗;
        String electricEnergyOfCoolingStation = "@" + totalEnergyCHPId + "@" + "+" + "@" + totalEnergyCWPId + "@" + "+" + "@" + totalEnergyCHId + "@" + "+" + "@" + totalEnergyCTId + "@";
        qstag.setTagname("electricEnergyOfCoolingStation");//冷站总电能
        qstag.setTagformula(electricEnergyOfCoolingStation);
        rows = qstagService.updateFormulaByTagName(dbName, qstag);
        if (rows == 1) {
            //更新成功
        }

        List<Qstag> localQsTagList = qstagService.findAllByItemDrIdAndItemId(dbName,0,"local");//local类型的drid默认是0
        if(CollectionUtils.isEmpty(localQsTagList)){
            return;
        }
        List<Qstag> energyQsTagList = qstagService.findAllByTagNameCNLike(dbName,"C%电量");
        if(CollectionUtils.isEmpty(energyQsTagList)){
            return;
        }
        for(Qstag qsTag : localQsTagList){
            String tagNameCN = qsTag.getTagnameCN();
            String tagName = qsTag.getTagname();
            String newRegName = null;
            if(tagNameCN != null && tagNameCN.contains("电能") && tagName != null && tagName.contains(".DN")){
                String key = FormatUtil.getCharAndNumber(tagNameCN);
                log.debug("key:{},tagNameCN:{}",key,tagNameCN);
                if(StringUtils.hasLength(key) && key.contains("-")){
                    key = key.substring(0,key.indexOf("-"));
                }
                //1号冷机电能、2号冷机电能
                if(tagNameCN.contains("冷机") && tagName.contains("LJ")){
                    if(tagNameCN.contains("总电能")){
                        newRegName = "CH总电量";
                    }else{
                        newRegName = "CH" + key + "电量";
                    }
                }else if(tagNameCN.contains("冷冻泵") && tagName.contains("LDB")){
                    if(tagNameCN.contains("总电能")){
                        newRegName = "CHP总电量";
                    }else{
                        newRegName = "CHP" + key + "电量";
                    }
                }else if(tagNameCN.contains("冷却塔") && (tagName.contains("LQT") || tagName.contains("CT"))){
                    if(tagNameCN.contains("总电能")){
                        newRegName = "CT总电量";
                    }else{
                        newRegName = "CT" + key + "电量";
                    }
                }else if(tagNameCN.contains("冷却泵") && tagName.contains("LQB")){
                    if(tagNameCN.contains("总电能")){
                        newRegName = "CWP总电量";
                    }else{
                        newRegName = "CWP" + key + "电量";
                    }
                }
                boolean find = false;
                if(newRegName != null && newRegName.contains("总电量")){
                    //总电量，总电能
                    LinkedList<Long> list = new LinkedList<>();
                    for(Qstag tempQsTag : energyQsTagList){
                        String tempTagNameCN = tempQsTag.getTagnameCN();
                        if(!StringUtils.hasLength(tempTagNameCN)){
                            continue;
                        }
                        String drTypeCode = newRegName.substring(0,newRegName.indexOf("总电量"));
                        String index = FormatUtil.getNumber(tempTagNameCN);
                        if(tempTagNameCN.trim().equals(drTypeCode + index + "电量")){
                            //匹配
                            list.add(tempQsTag.getTagid());
                            find = true;
                        }else if(newRegName.contains("CT") && tempTagNameCN.contains("CT") && newRegName.length() < tempTagNameCN.length()){

                        }
                    }
                    StringBuilder sb = new StringBuilder();
                    for(Long tagId : list){
                        sb.append("@" + tagId + "@" + "+");
                    }
                    String formula = sb.substring(0,sb.length()-1).toString();
                    qsTag.setTagformula(formula);
                }else if(newRegName != null){
                    //分电量，分电能
                    for(Qstag tempQsTag : energyQsTagList){
                        String tempTagnameCN = tempQsTag.getTagnameCN();
                        if(!StringUtils.hasLength(tempTagnameCN)){
                            continue;
                        }
                        if(tempTagnameCN.trim().equals(newRegName.trim())){
                            //匹配
                            qsTag.setTagformula("@" + tempQsTag.getTagid() + "@");
                            find = true;
                            break;
                        }else if(newRegName.contains("CT") && tempTagnameCN.contains("CT") && newRegName.length() < tempTagnameCN.length()){

                        }
                    }
                }
                //更新
                if(find){
                    qstagService.updateFormula(dbName,qsTag);
                }
            }
        }
    }

    /**
     * 设置和返回主机功率的公式
     * @return
     */
    private String getTotalChPowerFormula(String dbName,String type,String tagNameLike){
        StringBuilder totalChPowerFormula = new StringBuilder();
        List<Qstag> list = qstagService.findAllByTagNameCNLike(dbName,tagNameLike);
        if(list != null && list.size() > 0){
            list.forEach(qstag -> {
                String tagNameCN = qstag.getTagnameCN();
                String prefix = FormatUtil.getCharAndNumber(tagNameCN);
                String suffix = tagNameCN.substring(tagNameCN.indexOf(prefix) + prefix.length());
                if(StringUtils.hasLength(prefix) && prefix.contains("-")){
                    prefix = prefix.substring(0,prefix.length()-1);
                    if(prefix.contains("CHP")){
                        //冷冻泵功率,并过滤掉“功率因数”
                        if("功率".equals(suffix) || "电量".equals(suffix)){
                            if("CHP".equals(type) || "电量".equals(type)){
                                totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                            }
                        }
                    }else if(prefix.contains("CH") && prefix.charAt(2) != 'P'){
                        //冷机功率,并过滤掉“功率因数” “CH1变频器功率” “CH2压缩机功率”
                        if("功率".equals(suffix) || "电量".equals(suffix)){
                            if("CH".equals(type) || "电量".equals(type)){
                                totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                            }
                        }
                    }else if(prefix.contains("CT")){
                        //冷却塔功率,并过滤掉“功率因数”
                        if("功率".equals(suffix) || "电量".equals(suffix)){
                            if("CT".equals(type) || "电量".equals(type)){
                                totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");

                            }
                        }
                    }else if(prefix.contains("CWP")){
                        //冷却泵功率,并过滤掉“功率因数”
                        if("功率".equals(suffix) || "电量".equals(suffix)){
                            if("CWP".equals(type) || "电量".equals(type)){
                                totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                            }
                        }
                    }else if(tagNameCN.contains("制冷功率")){
                        if("制冷功率".equals(type)){
                            totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                        }
                    }else if(tagNameCN.contains("制热功率")){
                        if("制热功率".equals(type)){
                            totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                        }
                    }else if(!"local".equals(qstag.getItemid()) && (tagNameCN.contains("累计制冷量") || tagNameCN.contains("制冷量"))){
                        if("制冷量".equals(type)){
                            totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                        }
                    }else if(!"local".equals(qstag.getItemid()) && (tagNameCN.contains("累计散热量") || tagNameCN.contains("散热量"))){
                        if("散热量".equals(type)){
                            totalChPowerFormula.append("@"  + qstag.getTagid() + "@" + " + ");
                        }
                    }
                }
            });
        }
        String newFormula = totalChPowerFormula.toString();
        newFormula = StringUtils.hasLength(newFormula) ?  newFormula.trim() : "";
        if(StringUtils.hasLength(newFormula) && newFormula.lastIndexOf("+") == (newFormula.length()-1)){
            newFormula = newFormula.substring(0,newFormula.length() - 1).trim();
        }else{
            newFormula="";
        }
        return newFormula;
    }

    private void getParent(Long drTypeId,Map<Long,Drtypeinfo> map,Set<Long> setList){
        Drtypeinfo drtypeinfo = map.get(drTypeId);
        Long parentId = drtypeinfo.getParentId();
        if(parentId == 0){
            //drTypeId没有父ID
        }else{
            //递归找到所有父级
            setList.add(parentId);//找到一个父ID
            getParent(parentId,map,setList);
        }
    }

    public static int getLongestCommonSubstring(String a, String b){
        int m = a.length();
        int n = b.length();
        int max = 0;
        int[][] dp = new int[m][n];
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(a.charAt(i) == b.charAt(j)){
                    if(i==0 || j==0){
                        dp[i][j]=1;
                    }else{
                        dp[i][j] = dp[i-1][j-1]+1;
                    }
                    if(max < dp[i][j]){
                        max = dp[i][j];
                    }
                }
            }
        }
        return max;
    }

    /*public static void main(String[] args) {
        String s1 = "CT3通讯状态";
        String s2 = "CT4通讯状态";
        String s3 = "CT3_CT4通讯状态";
        int d = getLongestCommonSubstring(s1,s3);
        int f = getLongestCommonSubstring(s2,s3);
        System.out.println(d);
        System.out.println(f);
        String gg = FormatUtil.getCharAndNumber(s1);

        System.out.println(gg.substring(0,gg.length()-1));
        System.out.println(FormatUtil.getCharAndNumber(s2));

        System.out.println(getNumber("0.1Hz"));
        System.out.println(getNumber("0.1%"));
        System.out.println(getNumber("0.1℃"));
        System.out.println(getNumber("1"));
        System.out.println(getNumber("0.1A"));
        System.out.println(getNumber("0.025V"));
        System.out.println(getNumber("0.45KW"));
        System.out.println(getNumber("0.025KWH"));
        System.out.println(getNumber("0.01"));
        System.out.println(getNumber("m0.1V"));
        System.out.println(getNumber("10"));
        System.out.println(getNumber("10.01"));
        System.out.println(getNumber("1V"));
        System.out.println(getNumber("10.1"));
        System.out.println(getNumber("10.1%"));
        System.out.println(getNumber("10.1%%"));


        String tagNameCN = "功率因数";//CHP6功率因数
        String prefix = FormatUtil.getCharAndNumber(tagNameCN);
        String suffix = tagNameCN.substring(tagNameCN.indexOf(prefix) + prefix.length());
        System.out.println(tagNameCN.lastIndexOf("+") == (tagNameCN.length()-1));
        System.out.println(tagNameCN.substring(0,tagNameCN.length()-1));
//        if(prefix.contains("CH") && prefix.charAt(2) != 'P'){
//            System.out.println("wwwwwwwwwwwwwwwwwwwwwwwwwwwwww");
//        }
//        tagNameCN = "CHP1功率因数 +";//CHP6功率因数
//        prefix = FormatUtil.getCharAndNumber(tagNameCN);
//        if(prefix.contains("CH") && prefix.charAt(2) == 'P'){
//            System.out.println("qqqqqqqqqqqqqqqqqqqqqqqq");
//        }
    }*/


}
